Skip to content

Commit

Permalink
Implement complex number and ImaginaryUnit
Browse files Browse the repository at this point in the history
  • Loading branch information
fintarin committed Aug 7, 2023
1 parent c4ff06b commit 13ab2b2
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 1 deletion.
2 changes: 2 additions & 0 deletions include/fintamath/core/MathObjectTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum class MathObjectType : MathObjectTypeId {

Rational,
Real,
Complex,

IInteger = 8000,

Expand All @@ -68,6 +69,7 @@ enum class MathObjectType : MathObjectTypeId {
NegInf,
ComplexInf,
Undefined,
ImaginaryUnit,

IFunction = 11000,

Expand Down
23 changes: 23 additions & 0 deletions include/fintamath/literals/constants/ImaginaryUnit.hpp
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;
};

}
69 changes: 69 additions & 0 deletions include/fintamath/numbers/Complex.hpp
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 &divide(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);
};

}
14 changes: 14 additions & 0 deletions src/fintamath/config/ConverterConfig.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "fintamath/core/Converter.hpp"

#include "fintamath/numbers/Complex.hpp"
#include "fintamath/numbers/Integer.hpp"
#include "fintamath/numbers/Rational.hpp"
#include "fintamath/numbers/Real.hpp"
Expand Down Expand Up @@ -39,6 +40,19 @@ struct ConverterConfig {
Converter::add<Real, Rational>([](const Real & /*type*/, const Rational &value) {
return std::make_unique<Real>(value);
});

Converter::add<Complex, Complex>([](const Complex & /*type*/, const Complex &value) {
return std::make_unique<Complex>(value);
});
Converter::add<Complex, Integer>([](const Complex & /*type*/, const Integer &value) {
return std::make_unique<Complex>(value);
});
Converter::add<Complex, Rational>([](const Complex & /*type*/, const Rational &value) {
return std::make_unique<Complex>(value);
});
Converter::add<Complex, Real>([](const Complex & /*type*/, const Real &value) {
return std::make_unique<Complex>(value);
});
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/fintamath/config/ParserConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#include "fintamath/literals/constants/E.hpp"
#include "fintamath/literals/constants/False.hpp"
#include "fintamath/literals/constants/IConstant.hpp"
#include "fintamath/literals/constants/ImaginaryUnit.hpp"
#include "fintamath/literals/constants/Inf.hpp"
#include "fintamath/literals/constants/NegInf.hpp"
#include "fintamath/literals/constants/Pi.hpp"
Expand Down Expand Up @@ -157,7 +158,6 @@ struct ParserConfig {

INumber::registerType<IInteger>(&IInteger::parse);
INumber::registerType<Rational>();
INumber::registerType<Real>();

IInteger::registerType<Integer>();

Expand All @@ -173,6 +173,7 @@ struct ParserConfig {
IConstant::registerType<NegInf>();
IConstant::registerType<ComplexInf>();
IConstant::registerType<Undefined>();
IConstant::registerType<ImaginaryUnit>();

IFunction::registerType<Abs>();
IFunction::registerType<Log>();
Expand Down
9 changes: 9 additions & 0 deletions src/fintamath/literals/constants/ImaginaryUnit.cpp
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));
}

}
135 changes: 135 additions & 0 deletions src/fintamath/numbers/Complex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#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 {
// TODO!!! See symengine
throw InvalidInputBinaryOperatorException("<", toString(), rhs.toString());
}

bool Complex::more(const Complex &rhs) const {
// TODO!!! See symengine
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;
}

}

0 comments on commit 13ab2b2

Please sign in to comment.