diff --git a/poincare/include/poincare/great_common_divisor.h b/poincare/include/poincare/great_common_divisor.h index f01fc5dcf..d5a6c4ae3 100644 --- a/poincare/include/poincare/great_common_divisor.h +++ b/poincare/include/poincare/great_common_divisor.h @@ -42,7 +42,7 @@ public: static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("gcd", -2, &UntypedBuilderMultipleChildren); // Expression - Expression shallowReduce(Context * context); + Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression shallowBeautify(Context * context); }; diff --git a/poincare/include/poincare/least_common_multiple.h b/poincare/include/poincare/least_common_multiple.h index c65550ceb..1feda8cb7 100644 --- a/poincare/include/poincare/least_common_multiple.h +++ b/poincare/include/poincare/least_common_multiple.h @@ -42,7 +42,7 @@ public: static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("lcm", -2, &UntypedBuilderMultipleChildren); // Expression - Expression shallowReduce(Context * context); + Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression shallowBeautify(Context * context); }; diff --git a/poincare/include/poincare/n_ary_expression.h b/poincare/include/poincare/n_ary_expression.h index ed5a65846..64dedd156 100644 --- a/poincare/include/poincare/n_ary_expression.h +++ b/poincare/include/poincare/n_ary_expression.h @@ -55,7 +55,7 @@ protected: node()->sortChildrenInPlace(order, context, canSwapMatrices, canBeInterrupted); } NAryExpressionNode * node() const { return static_cast(Expression::node()); } - Expression checkChildrenAreRationalIntegers(Context * context); + Expression checkChildrenAreRationalIntegersAndUpdate(ExpressionNode::ReductionContext reductionContext); }; } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index a26abadea..cc407c892 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -289,12 +289,13 @@ bool Expression::hasDefinedComplexApproximation(Context * context, Preferences:: } /* We return true when both real and imaginary approximation are defined and * imaginary part is not null. */ - Expression imag = ImaginaryPart::Builder(*this); + Expression e = clone(); + Expression imag = ImaginaryPart::Builder(e); float b = imag.approximateToScalar(context, complexFormat, angleUnit); if (b == 0.0f || std::isinf(b) || std::isnan(b)) { return false; } - Expression real = RealPart::Builder(*this); + Expression real = RealPart::Builder(e); float a = real.approximateToScalar(context, complexFormat, angleUnit); if (std::isinf(a) || std::isnan(a)) { return false; diff --git a/poincare/src/great_common_divisor.cpp b/poincare/src/great_common_divisor.cpp index 95aa3205e..51d6a6fcc 100644 --- a/poincare/src/great_common_divisor.cpp +++ b/poincare/src/great_common_divisor.cpp @@ -16,7 +16,7 @@ int GreatCommonDivisorNode::serialize(char * buffer, int bufferSize, Preferences } Expression GreatCommonDivisorNode::shallowReduce(ReductionContext reductionContext) { - return GreatCommonDivisor(this).shallowReduce(reductionContext.context()); + return GreatCommonDivisor(this).shallowReduce(reductionContext); } Expression GreatCommonDivisorNode::shallowBeautify(ReductionContext reductionContext) { @@ -36,7 +36,7 @@ Expression GreatCommonDivisor::shallowBeautify(Context * context) { return *this; } -Expression GreatCommonDivisor::shallowReduce(Context * context) { +Expression GreatCommonDivisor::shallowReduce(ExpressionNode::ReductionContext reductionContext) { { Expression e = Expression::defaultShallowReduce(); e = e.defaultHandleUnitsInChildren(); @@ -51,7 +51,7 @@ Expression GreatCommonDivisor::shallowReduce(Context * context) { // Step 1: check that all children are compatible { - Expression checkChildren = checkChildrenAreRationalIntegers(context); + Expression checkChildren = checkChildrenAreRationalIntegersAndUpdate(reductionContext); if (!checkChildren.isUninitialized()) { return checkChildren; } diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index 9a1e50056..6d49b02a4 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -16,7 +16,7 @@ int LeastCommonMultipleNode::serialize(char * buffer, int bufferSize, Preference } Expression LeastCommonMultipleNode::shallowReduce(ReductionContext reductionContext) { - return LeastCommonMultiple(this).shallowReduce(reductionContext.context()); + return LeastCommonMultiple(this).shallowReduce(reductionContext); } Expression LeastCommonMultipleNode::shallowBeautify(ReductionContext reductionContext) { @@ -36,7 +36,7 @@ Expression LeastCommonMultiple::shallowBeautify(Context * context) { return *this; } -Expression LeastCommonMultiple::shallowReduce(Context * context) { +Expression LeastCommonMultiple::shallowReduce(ExpressionNode::ReductionContext reductionContext) { { Expression e = Expression::defaultShallowReduce(); e = e.defaultHandleUnitsInChildren(); @@ -51,7 +51,7 @@ Expression LeastCommonMultiple::shallowReduce(Context * context) { // Step 1: check that all children are compatible { - Expression checkChildren = checkChildrenAreRationalIntegers(context); + Expression checkChildren = checkChildrenAreRationalIntegersAndUpdate(reductionContext); if (!checkChildren.isUninitialized()) { return checkChildren; } diff --git a/poincare/src/n_ary_expression.cpp b/poincare/src/n_ary_expression.cpp index 2303cc0d4..a64be96c9 100644 --- a/poincare/src/n_ary_expression.cpp +++ b/poincare/src/n_ary_expression.cpp @@ -74,13 +74,26 @@ int NAryExpression::allChildrenAreReal(Context * context) const { return result; } -Expression NAryExpression::checkChildrenAreRationalIntegers(Context * context) { +Expression NAryExpression::checkChildrenAreRationalIntegersAndUpdate(ExpressionNode::ReductionContext reductionContext) { for (int i = 0; i < numberOfChildren(); ++i) { Expression c = childAtIndex(i); - if (c.deepIsMatrix(context)) { + if (c.deepIsMatrix(reductionContext.context())) { return replaceWithUndefinedInPlace(); } if (c.type() != ExpressionNode::Type::Rational) { + /* Replace expression with undefined if child can be approximated to a + * complex or finite non-integer number. Otherwise, rely on template + * approximations. hasDefinedComplexApproximation is given Cartesian + * complex format to force imaginary part approximation. */ + if (!c.isReal(reductionContext.context()) && c.hasDefinedComplexApproximation(reductionContext.context(), Preferences::ComplexFormat::Cartesian, reductionContext.angleUnit())) { + return replaceWithUndefinedInPlace(); + } + // If c was complex but with a null imaginary part, real part is checked. + float app = c.approximateToScalar(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()); + if (std::isfinite(app) && app != std::round(app)) { + return replaceWithUndefinedInPlace(); + } + // Note : Child could be replaced with the approximation (if finite) here. return *this; } if (!static_cast(c).isInteger()) {