From f84b3dc5c15c008926d806c569af98d200eefa9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 24 Mar 2020 12:19:14 +0100 Subject: [PATCH] [poincare] Power approximation: avoid approximating a power to 0 when one of the real/imaginary part was not null --- poincare/include/poincare/approximation_helper.h | 2 +- poincare/src/approximation_helper.cpp | 9 ++++++--- poincare/src/power.cpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/poincare/include/poincare/approximation_helper.h b/poincare/include/poincare/approximation_helper.h index 9b0b8ce17..20008c0d3 100644 --- a/poincare/include/poincare/approximation_helper.h +++ b/poincare/include/poincare/approximation_helper.h @@ -10,7 +10,7 @@ namespace Poincare { namespace ApproximationHelper { 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); + template std::complex NeglectRealOrImaginaryPartIfNeglectable(std::complex result, std::complex input1, std::complex input2 = 1.0, bool enableNullResult = true); template using ComplexCompute = Complex(*)(const std::complex, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit); template Evaluation Map(const ExpressionNode * expression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ComplexCompute compute); diff --git a/poincare/src/approximation_helper.cpp b/poincare/src/approximation_helper.cpp index 61c5f8d20..c82371cb4 100644 --- a/poincare/src/approximation_helper.cpp +++ b/poincare/src/approximation_helper.cpp @@ -37,7 +37,7 @@ template int ApproximationHelper::PositiveIntegerApproximationIfPos return absInt((int)scalar); } -template std::complex ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex result, std::complex input1, std::complex input2) { +template std::complex ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex result, std::complex input1, std::complex input2, bool enableNullResult) { /* Cheat: openbsd functions (cos, sin, tan, cosh, acos, pow...) are * numerical implementation and thus are approximative. * The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid @@ -47,6 +47,9 @@ template std::complex ApproximationHelper::NeglectRealOrImaginar * sin(1E-15)=1E-15. * We can't do that for all evaluation as the user can operate on values as * small as 1E-308 (in double) and most results still be correct. */ + if (!enableNullResult && (result.imag() == 0.0 || result.real() == 0.0)) { + return result; + } T magnitude1 = minimalNonNullMagnitudeOfParts(input1); T magnitude2 = minimalNonNullMagnitudeOfParts(input2); T precision = 10.0*Expression::Epsilon(); @@ -126,8 +129,8 @@ template MatrixComplex ApproximationHelper::ElementWiseOnComplexM 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); -template std::complex Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex,std::complex,std::complex); +template std::complex Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex,std::complex,std::complex,bool); +template std::complex Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex,std::complex,std::complex,bool); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); template Poincare::Evaluation Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute compute); template Poincare::Evaluation Poincare::ApproximationHelper::MapReduce(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexAndComplexReduction computeOnComplexes, Poincare::ApproximationHelper::ComplexAndMatrixReduction computeOnComplexAndMatrix, Poincare::ApproximationHelper::MatrixAndComplexReduction computeOnMatrixAndComplex, Poincare::ApproximationHelper::MatrixAndMatrixReduction computeOnMatrices); diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index c7362383e..dab83ee30 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -183,7 +183,7 @@ Complex PowerNode::compute(const std::complex c, const std::complex d, * so arg(c^d) = y*ln(r)+xθ. * We consider that arg[π] is negligeable if it is negligeable compared to * norm(d) = sqrt(x^2+y^2) and ln(r) = ln(norm(c)).*/ - return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d)); + return Complex::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d, false)); } // Layout