[poincare] Fix gcd and lcm approximations

This commit is contained in:
Émilie Feral
2019-12-13 10:59:20 +01:00
committed by LeaNumworks
parent c2f86e0806
commit 07ecc119ab
4 changed files with 34 additions and 21 deletions

View File

@@ -9,6 +9,7 @@
namespace Poincare {
namespace ApproximationHelper {
template <typename T> int IntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
template <typename T> std::complex<T> TruncateRealOrImaginaryPartAccordingToArgument(std::complex<T> c);
template <typename T> using ComplexCompute = Complex<T>(*)(const std::complex<T>, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);

View File

@@ -15,6 +15,18 @@ template <typename T> T absMod(T a, T b) {
return result > b/2 ? b-result : result;
}
static inline int absInt(int x) { return x < 0 ? -x : x; }
template <typename T> int ApproximationHelper::IntegerApproximationIfPossible(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();
if (std::isnan(scalar) || scalar != (int)scalar) {
*isUndefined = true;
return 0;
}
return absInt((int)scalar);
}
template <typename T> std::complex<T> ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument(std::complex<T> c) {
T arg = std::arg(c);
T precision = 10*Expression::Epsilon<T>();
@@ -92,6 +104,8 @@ template<typename T> MatrixComplex<T> ApproximationHelper::ElementWiseOnComplexM
return matrix;
}
template int Poincare::ApproximationHelper::IntegerApproximationIfPossible<float>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template int Poincare::ApproximationHelper::IntegerApproximationIfPossible<double>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template std::complex<float> Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument<float>(std::complex<float>);
template std::complex<double> Poincare::ApproximationHelper::TruncateRealOrImaginaryPartAccordingToArgument<double>(std::complex<double>);
template Poincare::Evaluation<float> Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute<float> compute);

View File

@@ -1,5 +1,6 @@
#include <poincare/great_common_divisor.h>
#include <poincare/approximation_helper.h>
#include <poincare/arithmetic.h>
#include <poincare/layout_helper.h>
#include <poincare/rational.h>
@@ -27,22 +28,20 @@ Expression GreatCommonDivisorNode::shallowReduce(ReductionContext reductionConte
template<typename T>
Evaluation<T> GreatCommonDivisorNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> f1Input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> f2Input = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit);
T f1 = f1Input.toScalar();
T f2 = f2Input.toScalar();
if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) {
bool isUndefined = false;
int a = ApproximationHelper::IntegerApproximationIfPossible<T>(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit);
int b = ApproximationHelper::IntegerApproximationIfPossible<T>(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit);
if (isUndefined) {
return Complex<T>::Undefined();
}
int a = (int)f2;
int b = (int)f1;
if (f1 > f2) {
if (b > a) {
int temp = b;
b = a;
a = (int)f1;
a = temp;
}
int r = 0;
while((int)b!=0){
r = a - ((int)(a/b))*b;
r = a - (a/b)*b;
a = b;
b = r;
}

View File

@@ -1,4 +1,5 @@
#include <poincare/least_common_multiple.h>
#include <poincare/approximation_helper.h>
#include <poincare/rational.h>
#include <poincare/undefined.h>
#include <poincare/arithmetic.h>
@@ -27,26 +28,24 @@ Expression LeastCommonMultipleNode::shallowReduce(ReductionContext reductionCont
template<typename T>
Evaluation<T> LeastCommonMultipleNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> f1Input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> f2Input = childAtIndex(1)->approximate(T(), context, complexFormat, angleUnit);
T f1 = f1Input.toScalar();
T f2 = f2Input.toScalar();
if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) {
bool isUndefined = false;
int a = ApproximationHelper::IntegerApproximationIfPossible<T>(childAtIndex(0), &isUndefined, context, complexFormat, angleUnit);
int b = ApproximationHelper::IntegerApproximationIfPossible<T>(childAtIndex(1), &isUndefined, context, complexFormat, angleUnit);
if (isUndefined) {
return Complex<T>::Undefined();
}
if (f1 == 0.0f || f2 == 0.0f) {
if (a == 0 || b == 0) {
return Complex<T>::Builder(0.0);
}
int a = (int)f2;
int b = (int)f1;
if (f1 > f2) {
if (b > a) {
int temp = b;
b = a;
a = (int)f1;
a = temp;
}
int product = a*b;
int r = 0;
while((int)b!=0){
r = a - ((int)(a/b))*b;
r = a - (a/b)*b;
a = b;
b = r;
}