diff --git a/poincare/include/poincare/sign_function.h b/poincare/include/poincare/sign_function.h index 36f476252..d2a845c0d 100644 --- a/poincare/include/poincare/sign_function.h +++ b/poincare/include/poincare/sign_function.h @@ -51,7 +51,7 @@ public: static Expression UntypedBuilder(Expression children) { return Builder(children.childAtIndex(0)); } static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("sign", 1, &UntypedBuilder); - Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit); + Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target); private: explicit SignFunction(Expression child) : Expression(TreePool::sharedPool()->createTreeNode()) { replaceChildAtIndexInPlace(0, child); diff --git a/poincare/src/complex_cartesian.cpp b/poincare/src/complex_cartesian.cpp index 96274f56b..289939dc0 100644 --- a/poincare/src/complex_cartesian.cpp +++ b/poincare/src/complex_cartesian.cpp @@ -94,7 +94,7 @@ Expression ComplexCartesian::argument(Context & context, Preferences::AngleUnit return sub; } else { // if b == 0, argument = (1-sign(a))*Pi/2 - Expression signa = SignFunction::Builder(a).shallowReduce(context, angleUnit); + Expression signa = SignFunction::Builder(a).shallowReduce(context, angleUnit, target); Subtraction sub(Rational(1), signa); signa.shallowReduce(context, angleUnit, target); Multiplication mul(Rational(1,2), Constant(Ion::Charset::SmallPi), sub); diff --git a/poincare/src/complex_helper.cpp b/poincare/src/complex_helper.cpp index e8e0541ec..4ad679be6 100644 --- a/poincare/src/complex_helper.cpp +++ b/poincare/src/complex_helper.cpp @@ -96,7 +96,7 @@ ComplexPolar ComplexHelper::complexPolarFromComplexCartesian(const ExpressionNod // Then, compute sign(b) * Pi/2 - arctan(a/b) argument = Subtraction( Multiplication( - SignFunction::Builder(b).shallowReduce(context, angleUnit), + SignFunction::Builder(b).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation), Division(Constant(Ion::Charset::SmallPi), Rational(2)).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation) ).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation), arcTangent @@ -106,7 +106,7 @@ ComplexPolar ComplexHelper::complexPolarFromComplexCartesian(const ExpressionNod argument = Multiplication( Subtraction( Rational(1), - SignFunction::Builder(a).shallowReduce(context, angleUnit) + SignFunction::Builder(a).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation) ).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation), Division(Constant(Ion::Charset::SmallPi), Rational(2)).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation) ).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation); diff --git a/poincare/src/sign_function.cpp b/poincare/src/sign_function.cpp index 7b4e3acd1..dac3de99b 100644 --- a/poincare/src/sign_function.cpp +++ b/poincare/src/sign_function.cpp @@ -32,7 +32,7 @@ int SignFunctionNode::serialize(char * buffer, int bufferSize, Preferences::Prin } Expression SignFunctionNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ReductionTarget target) { - return SignFunction(this).shallowReduce(context, angleUnit); + return SignFunction(this).shallowReduce(context, angleUnit, target); } template @@ -46,7 +46,7 @@ Complex SignFunctionNode::computeOnComplex(const std::complex c, Preferenc return Complex(1.0); } -Expression SignFunction::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { +Expression SignFunction::shallowReduce(Context & context, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) { { Expression e = Expression::defaultShallowReduce(context, angleUnit); if (e.isUndefined()) { @@ -59,16 +59,30 @@ Expression SignFunction::shallowReduce(Context & context, Preferences::AngleUnit } #endif Rational one(1); - if (childAtIndex(0).sign(&context, angleUnit) != ExpressionNode::Sign::Unknown) { - if (childAtIndex(0).sign(&context, angleUnit) == ExpressionNode::Sign::Negative) { + Expression child = childAtIndex(0); + ExpressionNode::Sign s = child.sign(&context, angleUnit); + if (s != ExpressionNode::Sign::Unknown) { + if (s == ExpressionNode::Sign::Negative) { one = Rational(-1); } } else { - Evaluation childApproximated = childAtIndex(0).node()->approximate(1.0f, context, angleUnit); + Evaluation childApproximated = child.node()->approximate(1.0f, context, angleUnit); assert(childApproximated.type() == EvaluationNode::Type::Complex); Complex c = static_cast&>(childApproximated); + // c has no sign (c is complex or NAN) if (std::isnan(c.imag()) || std::isnan(c.real()) || c.imag() != 0) { - return *this; + // sign(-x) = sign(x) + Expression oppChild = child.makePositiveAnyNegativeNumeralFactor(context, angleUnit); + if (oppChild.isUninitialized()) { + return *this; + } else { + Expression sign = *this; + Multiplication m(Rational(-1)); + replaceWithInPlace(m); + m.addChildAtIndexInPlace(sign, 1, 1); + sign.shallowReduce(context, angleUnit, target); + return m.shallowReduce(context, angleUnit, target); + } } if (c.real() < 0) { one = Rational(-1); diff --git a/poincare/src/square_root.cpp b/poincare/src/square_root.cpp index a42e94719..663cb6d5c 100644 --- a/poincare/src/square_root.cpp +++ b/poincare/src/square_root.cpp @@ -62,7 +62,7 @@ ComplexCartesian SquareRootNode::complexCartesian(Context & context, Preferences // a = sqrt(x^2+y^2)+x Multiplication real = complexCartesianHelper(Addition(norm.clone(), x.clone()), context, angleUnit); Multiplication imag = complexCartesianHelper(Subtraction(norm, x), context, angleUnit); - imag.addChildAtIndexInPlace(SignFunction::Builder(y).shallowReduce(context, angleUnit), imag.numberOfChildren(), imag.numberOfChildren()); + imag.addChildAtIndexInPlace(SignFunction::Builder(y).shallowReduce(context, angleUnit, ExpressionNode::ReductionTarget::BottomUpComputation), imag.numberOfChildren(), imag.numberOfChildren()); return ComplexCartesian::Builder( real.shallowReduce(context, angleUnit, ReductionTarget::BottomUpComputation), imag.shallowReduce(context, angleUnit, ReductionTarget::BottomUpComputation)