[poincare/approximation_helper] Changed the way to approximate

To prevent incorrect approximations, such as cos(1.5707963267949) = 0, we lowered the precision value. This way,
  the approximation is more selective. However, when ploting functions such as e^(i.pi+x), the float approximation fails
  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 a maximal precision -> epsilon_double = 1x10^(-15), and when it is a float, we accept more agressive approximations
 -> epsilon_float = 10 x 1x10^(-7).

Change-Id: I844ac52ade665f51fe6888db38f4485c193286d9
This commit is contained in:
Arthur Camouseigt
2020-06-11 11:57:57 +02:00
committed by Émilie Feral
parent 1f9d0b5810
commit 5569ba92a2
2 changed files with 21 additions and 2 deletions

View File

@@ -9,6 +9,7 @@
namespace Poincare {
namespace ApproximationHelper {
template <typename T> T Epsilon();
template <typename T> int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
template <typename T> std::complex<T> NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2 = 1.0, bool enableNullResult = true);

View File

@@ -27,6 +27,23 @@ template < typename T> T minimalNonNullMagnitudeOfParts(std::complex<T> 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<typename T>
T ApproximationHelper::Epsilon() {
static T precision = (sizeof(T) == sizeof(double)) ? 1E-15 : 1E-6f;
return precision;
}
template <typename T> int ApproximationHelper::PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) {
Evaluation<T> evaluation = expression->approximate(T(), context, complexFormat, angleUnit);
T scalar = evaluation.toScalar();
@@ -52,7 +69,7 @@ template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginar
}
T magnitude1 = minimalNonNullMagnitudeOfParts(input1);
T magnitude2 = minimalNonNullMagnitudeOfParts(input2);
T precision = ((T)10.0)*Expression::Epsilon<T>();
T precision = Epsilon<T>();
if (isNegligeable(result.imag(), precision, magnitude1, magnitude2)) {
result.imag(0);
}
@@ -126,7 +143,8 @@ template<typename T> MatrixComplex<T> ApproximationHelper::ElementWiseOnComplexM
matrix.setDimensions(m.numberOfRows(), m.numberOfColumns());
return matrix;
}
template float Poincare::ApproximationHelper::Epsilon<float>();
template double Poincare::ApproximationHelper::Epsilon<double>();
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<float>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<double>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template std::complex<float> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<float>(std::complex<float>,std::complex<float>,std::complex<float>,bool);