-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement complex number and ImaginaryUnit
- Loading branch information
Showing
15 changed files
with
1,336 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#pragma once | ||
|
||
#include "fintamath/literals/constants/IConstant.hpp" | ||
#include "fintamath/numbers/Complex.hpp" | ||
|
||
namespace fintamath { | ||
|
||
class ImaginaryUnit : public IConstantCRTP<Complex, ImaginaryUnit> { | ||
public: | ||
std::string toString() const override { | ||
return "I"; | ||
} | ||
|
||
static MathObjectTypeId getTypeIdStatic() { | ||
return MathObjectTypeId(MathObjectType::ImaginaryUnit); | ||
} | ||
|
||
protected: | ||
std::unique_ptr<IMathObject> call() const override; | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#pragma once | ||
|
||
#include "fintamath/numbers/Integer.hpp" | ||
#include "fintamath/numbers/Rational.hpp" | ||
#include "fintamath/numbers/Real.hpp" | ||
|
||
namespace fintamath { | ||
|
||
class Complex : public INumberCRTP<Complex> { | ||
public: | ||
Complex() = default; | ||
|
||
Complex(const Complex &rhs); | ||
|
||
Complex(Complex &&rhs) noexcept = default; | ||
|
||
Complex &operator=(const Complex &rhs); | ||
|
||
Complex &operator=(Complex &&rhs) noexcept = default; | ||
|
||
explicit Complex(const std::string &str); | ||
|
||
explicit Complex(const INumber &inReal, const INumber &inImag); | ||
|
||
explicit Complex(int64_t inReal, int64_t inImag); | ||
|
||
Complex(const Integer &rhs); | ||
|
||
Complex(const Rational &rhs); | ||
|
||
Complex(const Real &rhs); | ||
|
||
Complex(int64_t rhs); | ||
|
||
std::string toString() const override; | ||
|
||
std::unique_ptr<IMathObject> toMinimalObject() const override; | ||
|
||
bool isPrecise() const override; | ||
|
||
bool isComplex() const override; | ||
|
||
const INumber &real() const; | ||
|
||
const INumber &imag() const; | ||
|
||
static MathObjectTypeId getTypeIdStatic() { | ||
return MathObjectTypeId(MathObjectType::Complex); | ||
} | ||
|
||
protected: | ||
bool equals(const Complex &rhs) const override; | ||
|
||
bool less(const Complex &rhs) const override; | ||
|
||
bool more(const Complex &rhs) const override; | ||
|
||
Complex &add(const Complex &rhs) override; | ||
|
||
Complex &substract(const Complex &rhs) override; | ||
|
||
Complex &multiply(const Complex &rhs) override; | ||
|
||
Complex ÷(const Complex &rhs) override; | ||
|
||
Complex &negate() override; | ||
|
||
private: | ||
std::unique_ptr<INumber> re = std::make_unique<Integer>(0); | ||
std::unique_ptr<INumber> im = std::make_unique<Integer>(0); | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#include "fintamath/literals/constants/ImaginaryUnit.hpp" | ||
|
||
namespace fintamath { | ||
|
||
std::unique_ptr<IMathObject> ImaginaryUnit::call() const { | ||
return std::make_unique<Complex>(Integer(0), Integer(1)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
#include "fintamath/numbers/Complex.hpp" | ||
|
||
#include <algorithm> | ||
#include <stdexcept> | ||
|
||
#include "fintamath/exceptions/InvalidInputException.hpp" | ||
#include "fintamath/exceptions/UndefinedException.hpp" | ||
|
||
namespace fintamath { | ||
|
||
Complex::Complex(const Complex &rhs) : re(cast<INumber>(rhs.re->clone())), im(cast<INumber>(rhs.im->clone())) { | ||
} | ||
|
||
Complex &Complex::operator=(const Complex &rhs) { | ||
if (this != &rhs) { | ||
re = cast<INumber>(rhs.re->clone()); | ||
im = cast<INumber>(rhs.im->clone()); | ||
} | ||
|
||
return *this; | ||
} | ||
|
||
Complex::Complex(const std::string &str) { | ||
if (!str.empty() && str.back() == 'I') { | ||
im = INumber::parse(str.substr(0, str.length() - 1)); | ||
} | ||
else { | ||
re = INumber::parse(str); | ||
} | ||
|
||
if (!re || !im) { | ||
throw InvalidInputException(str); | ||
} | ||
} | ||
|
||
Complex::Complex(const INumber &inReal, const INumber &inImag) { | ||
if (is<Complex>(inReal) || is<Complex>(inImag)) { | ||
throw InvalidInputException("Nested complex numbers are not allowed"); | ||
} | ||
|
||
re = cast<INumber>(inReal.toMinimalObject()); | ||
im = cast<INumber>(inImag.toMinimalObject()); | ||
} | ||
|
||
Complex::Complex(int64_t inReal, int64_t inImag) : re(std::make_unique<Integer>(inReal)), | ||
im(std::make_unique<Integer>(inImag)) { | ||
} | ||
|
||
Complex::Complex(const Integer &rhs) : re(cast<INumber>(rhs.toMinimalObject())) { | ||
} | ||
|
||
Complex::Complex(const Rational &rhs) : re(cast<INumber>(rhs.toMinimalObject())) { | ||
} | ||
|
||
Complex::Complex(const Real &rhs) : re(cast<INumber>(rhs.toMinimalObject())) { | ||
} | ||
|
||
Complex::Complex(int64_t rhs) : re(std::make_unique<Integer>(rhs)) { | ||
} | ||
|
||
std::string Complex::toString() const { | ||
std::string res; | ||
|
||
if (*re != Integer(0)) { | ||
res += re->toString(); | ||
} | ||
|
||
if (*im != Integer(0)) { | ||
std::string imStr = im->toString(); | ||
bool isImNeg = false; | ||
|
||
if (imStr.front() == '-') { | ||
imStr = imStr.substr(1); | ||
isImNeg = true; | ||
} | ||
|
||
if (imStr == "1") { | ||
imStr.clear(); | ||
} | ||
else { | ||
imStr += " "; | ||
} | ||
|
||
if (!res.empty()) { | ||
res += isImNeg ? " - " : " + "; | ||
} | ||
else if (isImNeg) { | ||
res += "-"; | ||
} | ||
|
||
res += imStr + "I"; | ||
} | ||
|
||
if (res.empty()) { | ||
res = "0"; | ||
} | ||
|
||
return res; | ||
} | ||
|
||
std::unique_ptr<IMathObject> Complex::toMinimalObject() const { | ||
if (*im == Integer(0)) { | ||
return re->toMinimalObject(); | ||
} | ||
|
||
return clone(); | ||
} | ||
|
||
bool Complex::isPrecise() const { | ||
return !is<Real>(re) && !is<Real>(im); | ||
} | ||
|
||
bool Complex::isComplex() const { | ||
return *im != Integer(0); | ||
} | ||
|
||
const INumber &Complex::real() const { | ||
return *re; | ||
} | ||
|
||
const INumber &Complex::imag() const { | ||
return *im; | ||
} | ||
|
||
bool Complex::equals(const Complex &rhs) const { | ||
return *re == *rhs.re && *im == *rhs.im; | ||
} | ||
|
||
bool Complex::less(const Complex &rhs) const { | ||
if (*re == *rhs.re) { | ||
return *im < *rhs.im; | ||
} | ||
|
||
return *re < *rhs.re; | ||
} | ||
|
||
bool Complex::more(const Complex &rhs) const { | ||
if (*re == *rhs.re) { | ||
return *im > *rhs.im; | ||
} | ||
|
||
return *re > *rhs.re; | ||
} | ||
|
||
Complex &Complex::add(const Complex &rhs) { | ||
re = *re + *rhs.re; | ||
im = *im + *rhs.im; | ||
|
||
return *this; | ||
} | ||
|
||
Complex &Complex::substract(const Complex &rhs) { | ||
re = *re - *rhs.re; | ||
im = *im - *rhs.im; | ||
|
||
return *this; | ||
} | ||
|
||
// https://en.wikipedia.org/wiki/Complex_number#Multiplication_and_square | ||
Complex &Complex::multiply(const Complex &rhs) { | ||
Complex lhs = *this; | ||
|
||
auto &x = *lhs.re; | ||
auto &y = *lhs.im; | ||
auto &u = *rhs.re; | ||
auto &v = *rhs.im; | ||
|
||
re = *(x * u) - *(y * v); | ||
im = *(x * v) + *(y * u); | ||
|
||
return *this; | ||
} | ||
|
||
// https://en.wikipedia.org/wiki/Complex_number#Reciprocal_and_division | ||
Complex &Complex::divide(const Complex &rhs) { | ||
Complex lhs = *this; | ||
|
||
auto &x = *lhs.re; | ||
auto &y = *lhs.im; | ||
auto &u = *rhs.re; | ||
auto &v = *rhs.im; | ||
|
||
auto divisor = *(u * u) + *(v * v); | ||
|
||
if (is<Integer>(divisor)) { | ||
divisor = convert<Rational>(*divisor); | ||
} | ||
|
||
try { | ||
re = *(*(x * u) + *(y * v)) / *divisor; | ||
im = *(*(y * u) - *(x * v)) / *divisor; | ||
} | ||
catch (const UndefinedException &) { | ||
throw UndefinedBinaryOperatorException("/", toString(), rhs.toString()); | ||
} | ||
|
||
return *this; | ||
} | ||
|
||
Complex &Complex::negate() { | ||
re = -(*re); | ||
im = -(*im); | ||
return *this; | ||
} | ||
|
||
} |
Oops, something went wrong.