diff --git a/poincare/include/poincare/decimal.h b/poincare/include/poincare/decimal.h index 5b37b3e6d..4c5b2bace 100644 --- a/poincare/include/poincare/decimal.h +++ b/poincare/include/poincare/decimal.h @@ -86,6 +86,8 @@ private: class Decimal final : public Number { friend class Number; friend class DecimalNode; +template +friend class ComplexNode; public: static int Exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentIsNegative = false); Decimal(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, int exponent); diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index ff33fb582..2c26fc8b1 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -26,6 +26,8 @@ class Expression : public TreeHandle { friend class BinomialCoefficient; friend class Ceiling; friend class CommonLogarithm; + template + friend class ComplexNode; friend class ComplexArgument; friend class ComplexHelper; friend class ConfidenceInterval; @@ -288,6 +290,10 @@ private: Expression defaultReplaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression expression); int defaultGetPolynomialCoefficients(Context & context, const char * symbol, Expression expression[]) const; + /* Builder */ + typedef Expression (*TransformExpression)(Expression e); + static Expression CreateComplexExpression(Expression ra, Expression tb, Preferences::ComplexFormat complexFormat, bool undefined, bool isZeroRa, bool isOneRa, bool isZeroTb, bool isOneTb, bool isMinusOneTb, bool isNegativeTb, TransformExpression inverse); + /* Expression roots/extrema solver*/ constexpr static double k_solverPrecision = 1.0E-5; constexpr static double k_sqrtEps = 1.4901161193847656E-8; // sqrt(DBL_EPSILON) diff --git a/poincare/src/complex.cpp b/poincare/src/complex.cpp index 2319f2eec..76e878db4 100644 --- a/poincare/src/complex.cpp +++ b/poincare/src/complex.cpp @@ -42,67 +42,24 @@ T ComplexNode::toScalar() const { template Expression ComplexNode::complexToExpression(Preferences::ComplexFormat complexFormat) const { - if (std::isnan(this->real()) || std::isnan(this->imag())) { - return Undefined(); - } + T ra, tb; if (complexFormat == Preferences::ComplexFormat::Cartesian) { - Expression real; - Expression imag; - if (this->real() != 0 || this->imag() == 0) { - real = Number::DecimalNumber(this->real()); - } - if (this->imag() != 0) { - if (this->imag() == 1.0 || this->imag() == -1) { - imag = Constant(Ion::Charset::IComplex); - } else if (this->imag() > 0) { - imag = Multiplication(Number::DecimalNumber(this->imag()), Constant(Ion::Charset::IComplex)); - } else { - imag = Multiplication(Number::DecimalNumber(-this->imag()), Constant(Ion::Charset::IComplex)); - } - } - if (imag.isUninitialized()) { - return real; - } else if (real.isUninitialized()) { - if (this->imag() > 0) { - return imag; - } else { - return Opposite(imag); - } - return imag; - } else if (this->imag() > 0) { - return Addition(real, imag); - } else { - return Subtraction(real, imag); - } - } - assert(complexFormat == Preferences::ComplexFormat::Polar); - Expression norm; - Expression exp; - T r = std::abs(*this); - T th = std::arg(*this); - if (r != 1 || th == 0) { - norm = Number::DecimalNumber(r); - } - if (r != 0 && th != 0) { - Expression arg; - if (th == 1.0) { - arg = Constant(Ion::Charset::IComplex); - } else if (th == -1.0) { - arg = Opposite(Constant(Ion::Charset::IComplex)); - } else if (th > 0) { - arg = Multiplication(Number::DecimalNumber(th), Constant(Ion::Charset::IComplex)); - } else { - arg = Opposite(Multiplication(Number::DecimalNumber(-th), Constant(Ion::Charset::IComplex))); - } - exp = Power(Constant(Ion::Charset::Exponential), arg); - } - if (exp.isUninitialized()) { - return norm; - } else if (norm.isUninitialized()) { - return exp; + ra = this->real(); + tb = this->imag(); } else { - return Multiplication(norm, exp); + ra = std::abs(*this); + tb = std::arg(*this); } + return Expression::CreateComplexExpression( + Number::DecimalNumber(ra), + Number::DecimalNumber(tb), + complexFormat, + (std::isnan(this->real()) || std::isnan(this->imag())), + ra == 0.0, ra == 1.0, tb == 0.0, tb == 1.0, tb == -1.0, tb < 0.0, + [](Expression e) { + assert(e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Rational || e.type() == ExpressionNode::Type::Float || e.type() == ExpressionNode::Type::Decimal || e.type() == ExpressionNode::Type::Infinity); + return Expression(static_cast(e).setSign(ExpressionNode::Sign::Positive)); } + ); } template diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 04adadb99..061eee666 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -455,6 +455,75 @@ U Expression::epsilon() { return epsilon; } +/* Builder */ + +Expression Expression::CreateComplexExpression(Expression ra, Expression tb, Preferences::ComplexFormat complexFormat, bool undefined, bool isZeroRa, bool isOneRa, bool isZeroTb, bool isOneTb, bool isMinusOneTb, bool isNegativeTb, TransformExpression inverse) { + if (undefined) { + return Undefined(); + } + switch (complexFormat) { + case Preferences::ComplexFormat::Cartesian: + { + Expression real; + Expression imag; + if (!isZeroRa || isZeroTb) { + real = ra; + } + if (!isZeroTb) { + if (isOneTb || isMinusOneTb) { + imag = Constant(Ion::Charset::IComplex); + } else if (isNegativeTb) { + imag = Multiplication(inverse(tb), Constant(Ion::Charset::IComplex)); + } else { + imag = Multiplication(tb , Constant(Ion::Charset::IComplex)); + } + } + if (imag.isUninitialized()) { + return real; + } else if (real.isUninitialized()) { + if (isNegativeTb) { + return Opposite(imag); + } else { + return imag; + } + } else if (isNegativeTb) { + return Subtraction(real, imag); + } else { + return Addition(real, imag); + } + } + default: + { + assert(complexFormat == Preferences::ComplexFormat::Polar); + Expression norm; + Expression exp; + if (!isOneRa || isZeroTb) { + norm = ra; + } + if (!isZeroRa && !isZeroTb) { + Expression arg; + if (isOneTb) { + arg = Constant(Ion::Charset::IComplex); + } else if (isMinusOneTb) { + arg = Opposite(Constant(Ion::Charset::IComplex)); + } else if (isNegativeTb) { + arg = Opposite(Multiplication(inverse(tb), Constant(Ion::Charset::IComplex))); + } else { + arg = Multiplication(tb, Constant(Ion::Charset::IComplex)); + } + exp = Power(Constant(Ion::Charset::Exponential), arg); + } + if (exp.isUninitialized()) { + return norm; + } else if (norm.isUninitialized()) { + return exp; + } else { + return Multiplication(norm, exp); + } + } + } +} + /* Expression roots/extrema solver*/ typename Expression::Coordinate2D Expression::nextMinimum(const char * symbol, double start, double step, double max, Context & context, Preferences::AngleUnit angleUnit) const {