-
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
7 changed files
with
253 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,23 @@ | ||
#pragma once | ||
|
||
#include "fintamath/literals/Boolean.hpp" | ||
#include "fintamath/literals/constants/IConstant.hpp" | ||
#include "fintamath/numbers/Complex.hpp" | ||
|
||
namespace fintamath { | ||
|
||
class ImaginaryUnit : public IConstantCRTP<Boolean, ImaginaryUnit> { | ||
public: | ||
std::string toString() const override { | ||
return Complex(Integer(0), Integer(1)).toString(); | ||
} | ||
|
||
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,69 @@ | ||
#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); | ||
|
||
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; | ||
|
||
Complex precise(uint8_t precision) const; | ||
|
||
const Integer &real() const; | ||
|
||
const Integer &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
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,133 @@ | ||
#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) { | ||
re = INumber::parse(str); | ||
} | ||
|
||
Complex::Complex(const INumber &inReal, const INumber &inImaginary) { | ||
if (is<Complex>(inReal) || is<Complex>(inImaginary)) { | ||
throw InvalidInputException("Nested complex numbers are not allowed"); | ||
} | ||
|
||
re = cast<INumber>(inReal.clone()); | ||
im = cast<INumber>(inImaginary.clone()); | ||
} | ||
|
||
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)) { | ||
if (!res.empty()) { | ||
res += " + "; | ||
} | ||
|
||
res += im->toString() + "I"; | ||
} | ||
|
||
if (res.empty()) { | ||
res = "0"; | ||
} | ||
|
||
return res; | ||
} | ||
|
||
std::unique_ptr<IMathObject> Complex::toMinimalObject() const { | ||
if (*im == Integer(0)) { | ||
return re->clone(); | ||
} | ||
return clone(); | ||
} | ||
|
||
Complex Complex::precise(uint8_t precision) const { | ||
Complex res = *this; | ||
res.re = std::make_unique<Real>(convert<Real>(*re).precise(precision)); | ||
res.im = std::make_unique<Real>(convert<Real>(*im).precise(precision)); | ||
return res; | ||
} | ||
|
||
bool Complex::equals(const Complex &rhs) const { | ||
return re == rhs.re && im == rhs.im; | ||
} | ||
|
||
bool Complex::less(const Complex &rhs) const { | ||
throw InvalidInputBinaryOperatorException("<", toString(), rhs.toString()); | ||
} | ||
|
||
bool Complex::more(const Complex &rhs) const { | ||
throw InvalidInputBinaryOperatorException(">", toString(), rhs.toString()); | ||
} | ||
|
||
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) { | ||
auto lhsRe = cast<INumber>(re->clone()); | ||
auto lhsIm = cast<INumber>(im->clone()); | ||
re = *(*lhsRe * *rhs.re) + *(*lhsIm * *rhs.im); | ||
im = *(*lhsRe * *rhs.im) + *(*lhsIm * *rhs.re); | ||
return *this; | ||
} | ||
|
||
// https://en.wikipedia.org/wiki/Complex_number#Reciprocal_and_division | ||
Complex &Complex::divide(const Complex &rhs) { | ||
auto lhsRe = cast<INumber>(re->clone()); | ||
auto lhsIm = cast<INumber>(im->clone()); | ||
auto divisor = *(*rhs.re * *rhs.re) + *(*rhs.im * *rhs.im); | ||
re = *(*(*lhsRe * *rhs.re) + *(*lhsIm * *rhs.im)) / *divisor; | ||
im = *(*(*lhsIm * *rhs.re) - *(*lhsRe * *rhs.im)) / *divisor; | ||
return *this; | ||
} | ||
|
||
Complex &Complex::negate() { | ||
re = -(*re); | ||
im = -(*im); | ||
return *this; | ||
} | ||
|
||
} |