diff --git a/poincare/include/poincare/approximation_helper.h b/poincare/include/poincare/approximation_helper.h index 20008c0d3..b16869948 100644 --- a/poincare/include/poincare/approximation_helper.h +++ b/poincare/include/poincare/approximation_helper.h @@ -9,6 +9,7 @@ namespace Poincare { namespace ApproximationHelper { + template T Epsilon(); template int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); template std::complex NeglectRealOrImaginaryPartIfNeglectable(std::complex result, std::complex input1, std::complex input2 = 1.0, bool enableNullResult = true); diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 30439ad9c..8224024fa 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -27,6 +27,23 @@ template < typename T> T minimalNonNullMagnitudeOfParts(std::complex c) { static inline int absInt(int x) { return x < 0 ? -x : x; } +/* To prevent incorrect approximations, such as cos(1.5707963267949) = 0 + * we made the neglect threshold stricter. This way, the approximation is more + * selective. + * However, when ploting functions such as e^(i.pi+x), the float approximation + * fails by giving non-real results and therefore, the function appears "undef". + * As a result we created two functions Epsilon that behave differently + * according to the number's type. When it is a double we want maximal precision + * -> precision_double = 1x10^(-15). + * When it is a float, we accept more agressive approximations + * -> precision_float = x10^(-6). */ + +template +T ApproximationHelper::Epsilon() { + static T precision = (sizeof(T) == sizeof(double)) ? 1E-15 : 1E-6f; + return precision; +} + template int ApproximationHelper::PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { Evaluation evaluation = expression->approximate(T(), context, complexFormat, angleUnit); T scalar = evaluation.toScalar(); @@ -52,7 +69,7 @@ template std::complex ApproximationHelper::NeglectRealOrImaginar } T magnitude1 = minimalNonNullMagnitudeOfParts(input1); T magnitude2 = minimalNonNullMagnitudeOfParts(input2); - T precision = ((T)10.0)*Expression::Epsilon(); + T precision = Epsilon(); if (isNegligeable(result.imag(), precision, magnitude1, magnitude2)) { result.imag(0); } @@ -126,7 +143,8 @@ template MatrixComplex ApproximationHelper::ElementWiseOnComplexM matrix.setDimensions(m.numberOfRows(), m.numberOfColumns()); return matrix; } - +template float Poincare::ApproximationHelper::Epsilon(); +template double Poincare::ApproximationHelper::Epsilon(); template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit); template std::complex Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex,std::complex,std::complex,bool);