From 72d1370cff33c9eba1e35167abbff2a264b3f8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 14 Jan 2020 11:30:06 +0100 Subject: [PATCH] [poincare] Returns a RealUndefined evaluation for Expression that are always real. This avoids that floor(i) is simplified to (undef, 0) but approximates to (undef, undef) --- poincare/include/poincare/complex.h | 3 +++ poincare/src/ceiling.cpp | 2 +- poincare/src/confidence_interval.cpp | 2 +- poincare/src/derivative.cpp | 4 ++-- poincare/src/division_quotient.cpp | 2 +- poincare/src/division_remainder.cpp | 2 +- poincare/src/factorial.cpp | 2 +- poincare/src/floor.cpp | 2 +- poincare/src/frac_part.cpp | 2 +- poincare/src/great_common_divisor.cpp | 2 +- poincare/src/integral.cpp | 2 +- poincare/src/least_common_multiple.cpp | 2 +- poincare/src/permute_coefficient.cpp | 2 +- poincare/src/prediction_interval.cpp | 2 +- poincare/src/randint.cpp | 2 +- poincare/src/round.cpp | 2 +- poincare/src/sign_function.cpp | 2 +- 17 files changed, 20 insertions(+), 17 deletions(-) diff --git a/poincare/include/poincare/complex.h b/poincare/include/poincare/complex.h index 1f9e82652..e8e92690d 100644 --- a/poincare/include/poincare/complex.h +++ b/poincare/include/poincare/complex.h @@ -45,6 +45,9 @@ public: static Complex Undefined() { return Complex::Builder(NAN, NAN); } + static Complex RealUndefined() { + return Complex::Builder(NAN, 0.0); + } std::complex stdComplex() { return *node(); } T real() { return node()->real(); } T imag() { return node()->imag(); } diff --git a/poincare/src/ceiling.cpp b/poincare/src/ceiling.cpp index 352af9e09..9700df2fb 100644 --- a/poincare/src/ceiling.cpp +++ b/poincare/src/ceiling.cpp @@ -26,7 +26,7 @@ int CeilingNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloa template Complex CeilingNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { if (c.imag() != 0) { - return Complex::Undefined(); + return Complex::RealUndefined(); } return Complex::Builder(std::ceil(c.real())); } diff --git a/poincare/src/confidence_interval.cpp b/poincare/src/confidence_interval.cpp index 72199a1e6..9e30edde7 100644 --- a/poincare/src/confidence_interval.cpp +++ b/poincare/src/confidence_interval.cpp @@ -37,7 +37,7 @@ Evaluation ConfidenceIntervalNode::templatedApproximate(Context * context, Pr T f = static_cast &>(fInput).toScalar(); T n = static_cast &>(nInput).toScalar(); if (std::isnan(f) || std::isnan(n) || n != (int)n || n < 0 || f < 0 || f > 1) { - return Complex::Undefined(); + return Complex::RealUndefined(); } std::complex operands[2]; operands[0] = std::complex(f - 1/std::sqrt(n)); diff --git a/poincare/src/derivative.cpp b/poincare/src/derivative.cpp index 4f6656f32..74fe60cb4 100644 --- a/poincare/src/derivative.cpp +++ b/poincare/src/derivative.cpp @@ -46,7 +46,7 @@ Evaluation DerivativeNode::templatedApproximate(Context * context, Preference T functionValue = approximateWithArgument(evaluationArgument, context, complexFormat, angleUnit); // No complex/matrix version of Derivative if (std::isnan(evaluationArgument) || std::isnan(functionValue)) { - return Complex::Undefined(); + return Complex::RealUndefined(); } T error = sizeof(T) == sizeof(double) ? DBL_MAX : FLT_MAX; @@ -71,7 +71,7 @@ Evaluation DerivativeNode::templatedApproximate(Context * context, Preference || (std::fabs(result) < k_maxErrorRateOnApproximation && std::fabs(error) > std::fabs(result)) || (std::fabs(result) >= k_maxErrorRateOnApproximation && std::fabs(error/result) > k_maxErrorRateOnApproximation)) { - return Complex::Undefined(); + return Complex::RealUndefined(); } static T min = sizeof(T) == sizeof(double) ? DBL_MIN : FLT_MIN; if (std::fabs(error) < min) { diff --git a/poincare/src/division_quotient.cpp b/poincare/src/division_quotient.cpp index efa252e9d..99b141ad4 100644 --- a/poincare/src/division_quotient.cpp +++ b/poincare/src/division_quotient.cpp @@ -30,7 +30,7 @@ Evaluation DivisionQuotientNode::templatedApproximate(Context * context, Pref T f1 = f1Input.toScalar(); T f2 = f2Input.toScalar(); if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) { - return Complex::Undefined(); + return Complex::RealUndefined(); } return Complex::Builder(std::floor(f1/f2)); } diff --git a/poincare/src/division_remainder.cpp b/poincare/src/division_remainder.cpp index c235c7000..457d1b163 100644 --- a/poincare/src/division_remainder.cpp +++ b/poincare/src/division_remainder.cpp @@ -31,7 +31,7 @@ Evaluation DivisionRemainderNode::templatedApproximate(Context * context, Pre T f1 = f1Input.toScalar(); T f2 = f2Input.toScalar(); if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) { - return Complex::Undefined(); + return Complex::RealUndefined(); } return Complex::Builder(std::round(f1-f2*std::floor(f1/f2))); } diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index 28c1ddfc0..84d97ad9e 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -54,7 +54,7 @@ template Complex FactorialNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { T n = c.real(); if (c.imag() != 0 || std::isnan(n) || n != (int)n || n < 0) { - return Complex::Undefined(); + return Complex::RealUndefined(); } T result = 1; for (int i = 1; i <= (int)n; i++) { diff --git a/poincare/src/floor.cpp b/poincare/src/floor.cpp index e7841a0a5..f195e82c3 100644 --- a/poincare/src/floor.cpp +++ b/poincare/src/floor.cpp @@ -26,7 +26,7 @@ int FloorNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatM template Complex FloorNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { if (c.imag() != 0) { - return Complex::Undefined(); + return Complex::RealUndefined(); } return Complex::Builder(std::floor(c.real())); } diff --git a/poincare/src/frac_part.cpp b/poincare/src/frac_part.cpp index 4ca63fe07..0b903399b 100644 --- a/poincare/src/frac_part.cpp +++ b/poincare/src/frac_part.cpp @@ -26,7 +26,7 @@ Expression FracPartNode::shallowReduce(ReductionContext reductionContext) { template Complex FracPartNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { if (c.imag() != 0) { - return Complex::Undefined(); + return Complex::RealUndefined(); } return Complex::Builder(c.real()-std::floor(c.real())); } diff --git a/poincare/src/great_common_divisor.cpp b/poincare/src/great_common_divisor.cpp index d9e9faec0..ec0c7a31b 100644 --- a/poincare/src/great_common_divisor.cpp +++ b/poincare/src/great_common_divisor.cpp @@ -32,7 +32,7 @@ Evaluation GreatCommonDivisorNode::templatedApproximate(Context * context, Pr int a = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); int b = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); if (isUndefined) { - return Complex::Undefined(); + return Complex::RealUndefined(); } if (b > a) { int temp = b; diff --git a/poincare/src/integral.cpp b/poincare/src/integral.cpp index 01ec6549d..fa9ce0ff9 100644 --- a/poincare/src/integral.cpp +++ b/poincare/src/integral.cpp @@ -50,7 +50,7 @@ Evaluation IntegralNode::templatedApproximate(Context * context, Preferences: T a = aInput.toScalar(); T b = bInput.toScalar(); if (std::isnan(a) || std::isnan(b)) { - return Complex::Undefined(); + return Complex::RealUndefined(); } #ifdef LAGRANGE_METHOD T result = lagrangeGaussQuadrature(a, b, context, complexFormat, angleUnit); diff --git a/poincare/src/least_common_multiple.cpp b/poincare/src/least_common_multiple.cpp index cb356e338..e9828820a 100644 --- a/poincare/src/least_common_multiple.cpp +++ b/poincare/src/least_common_multiple.cpp @@ -32,7 +32,7 @@ Evaluation LeastCommonMultipleNode::templatedApproximate(Context * context, P int a = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit); int b = ApproximationHelper::PositiveIntegerApproximationIfPossible(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit); if (isUndefined) { - return Complex::Undefined(); + return Complex::RealUndefined(); } if (a == 0 || b == 0) { return Complex::Builder(0.0); diff --git a/poincare/src/permute_coefficient.cpp b/poincare/src/permute_coefficient.cpp index 8a3599972..e26b39730 100644 --- a/poincare/src/permute_coefficient.cpp +++ b/poincare/src/permute_coefficient.cpp @@ -34,7 +34,7 @@ Evaluation PermuteCoefficientNode::templatedApproximate(Context * context, Pr T n = nInput.toScalar(); T k = kInput.toScalar(); if (std::isnan(n) || std::isnan(k) || n != std::round(n) || k != std::round(k) || n < 0.0f || k < 0.0f) { - return Complex::Undefined(); + return Complex::RealUndefined(); } if (k > n) { return Complex::Builder(0.0); diff --git a/poincare/src/prediction_interval.cpp b/poincare/src/prediction_interval.cpp index cb5a2be95..16501cf44 100644 --- a/poincare/src/prediction_interval.cpp +++ b/poincare/src/prediction_interval.cpp @@ -37,7 +37,7 @@ Evaluation PredictionIntervalNode::templatedApproximate(Context * context, Pr T p = static_cast &>(pInput).toScalar(); T n = static_cast &>(nInput).toScalar(); if (std::isnan(p) || std::isnan(n) || n != (int)n || n < 0 || p < 0 || p > 1) { - return Complex::Undefined(); + return Complex::RealUndefined(); } std::complex operands[2]; operands[0] = std::complex(p - 1.96*std::sqrt(p*(1.0-p))/std::sqrt(n)); diff --git a/poincare/src/randint.cpp b/poincare/src/randint.cpp index 9872d3c0e..498982d89 100644 --- a/poincare/src/randint.cpp +++ b/poincare/src/randint.cpp @@ -50,7 +50,7 @@ template Evaluation RandintNode::templateApproximate(Context * c || a > b || a != (int)a || b != (int)b || (Expression::Epsilon()*(b+1.0-a) > 1.0)) { - return Complex::Undefined(); + return Complex::RealUndefined(); } T result = std::floor(Random::random()*(b+1.0-a)+a); return Complex::Builder(result); diff --git a/poincare/src/round.cpp b/poincare/src/round.cpp index 320e0ac05..92bd9c45e 100644 --- a/poincare/src/round.cpp +++ b/poincare/src/round.cpp @@ -33,7 +33,7 @@ Evaluation RoundNode::templatedApproximate(Context * context, Preferences::Co T f1 = f1Input.toScalar(); T f2 = f2Input.toScalar(); if (std::isnan(f2) || f2 != std::round(f2)) { - return Complex::Undefined(); + return Complex::RealUndefined(); } T err = std::pow(10, std::floor(f2)); return Complex::Builder(std::round(f1*err)/err); diff --git a/poincare/src/sign_function.cpp b/poincare/src/sign_function.cpp index ff47a461c..285cd5cb7 100644 --- a/poincare/src/sign_function.cpp +++ b/poincare/src/sign_function.cpp @@ -42,7 +42,7 @@ Expression SignFunctionNode::shallowReduce(ReductionContext reductionContext) { template Complex SignFunctionNode::computeOnComplex(const std::complex c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) { if (c.imag() != 0 || std::isnan(c.real())) { - return Complex::Undefined(); + return Complex::RealUndefined(); } if (c.real() == 0) { return Complex::Builder(0.0);