From cb432e165e0f63ccb6bc7b836613601bd794a37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 20 Nov 2017 11:16:01 +0100 Subject: [PATCH] [poincare] Cap binomial and permute coefficient reducing Change-Id: Ib0c08a9788d77025e709d295bf05f30de50e9253 --- .../include/poincare/binomial_coefficient.h | 1 + .../include/poincare/permute_coefficient.h | 1 + poincare/src/binomial_coefficient.cpp | 19 ++++++++++--------- poincare/src/permute_coefficient.cpp | 16 +++++++++------- poincare/test/simplify_easy.cpp | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/poincare/include/poincare/binomial_coefficient.h b/poincare/include/poincare/binomial_coefficient.h index 4fe57c91d..f0215e7c8 100644 --- a/poincare/include/poincare/binomial_coefficient.h +++ b/poincare/include/poincare/binomial_coefficient.h @@ -12,6 +12,7 @@ public: Type type() const override; Expression * clone() const override; private: + constexpr static int k_maxNValue = 300; /* Layout */ ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; int writeTextInBuffer(char * buffer, int bufferSize) const override { diff --git a/poincare/include/poincare/permute_coefficient.h b/poincare/include/poincare/permute_coefficient.h index 9f251c617..0cf54c594 100644 --- a/poincare/include/poincare/permute_coefficient.h +++ b/poincare/include/poincare/permute_coefficient.h @@ -13,6 +13,7 @@ public: Type type() const override; Expression * clone() const override; private: + constexpr static int k_maxNValue = 100; /* Layout */ ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override { return LayoutEngine::createPrefixLayout(this, floatDisplayMode, complexFormat, name()); diff --git a/poincare/src/binomial_coefficient.cpp b/poincare/src/binomial_coefficient.cpp index 4b5ec7151..f33c5a0e8 100644 --- a/poincare/src/binomial_coefficient.cpp +++ b/poincare/src/binomial_coefficient.cpp @@ -57,17 +57,15 @@ Expression * BinomialCoefficient::shallowReduce(Context& context, AngleUnit angl if (n.isLowerThan(k)) { return replaceWith(new Undefined(), true); } + /* if n is too big, we do not reduce to avoid too long computation. + * The binomial coefficient will be evaluate approximatively later */ + if (Integer(k_maxNValue).isLowerThan(n)) { + return this; + } Rational result(1); Integer kBis = Integer::Subtraction(n, k); k = kBis.isLowerThan(k) ? kBis : k; - // Out of bounds - if (Integer(k_maxNumberOfSteps).isLowerThan(k)) { - return replaceWith(new Undefined(), true); - } - int clippedK = k.extractedInt(); // Authorized because k < k_maxNumberOfSteps - /* TODO: cap n and k -> if k or n too big, do not reduce to avoid too long - * computation. The binomial coefficient will be evaluate approximatively - * later */ + int clippedK = k.extractedInt(); // Authorized because k < n < k_maxNValue for (int i = 0; i < clippedK; i++) { Rational factor = Rational(Integer::Subtraction(n, Integer(i)), Integer::Subtraction(k, Integer(i))); result = Rational::Multiplication(result, factor); @@ -96,12 +94,15 @@ Expression * BinomialCoefficient::templatedEvaluate(Context& context, AngleUnit delete nInput; delete kInput; k = k > (n-k) ? n-k : k; - if (isnan(n) || isnan(k) || n != std::round(n) || k != std::round(k) || k > n || k < 0 || n < 0 || k > k_maxNumberOfSteps) { + if (isnan(n) || isnan(k) || n != std::round(n) || k != std::round(k) || k > n || k < 0 || n < 0) { return new Complex(Complex::Float(NAN)); } T result = 1; for (int i = 0; i < k; i++) { result *= (n-(T)i)/(k-(T)i); + if (isinf(result)) { + return new Complex(Complex::Float(result)); + } } return new Complex(Complex::Float(std::round(result))); } diff --git a/poincare/src/permute_coefficient.cpp b/poincare/src/permute_coefficient.cpp index b0d887463..c0639b7e8 100644 --- a/poincare/src/permute_coefficient.cpp +++ b/poincare/src/permute_coefficient.cpp @@ -53,14 +53,13 @@ Expression * PermuteCoefficient::shallowReduce(Context& context, AngleUnit angle if (n.isLowerThan(k)) { return replaceWith(new Rational(0), true); } - if (Integer(k_maxNumberOfSteps).isLowerThan(k)) { - return replaceWith(new Undefined(), true); + /* if n is too big, we do not reduce to avoid too long computation. + * The permute coefficient will be evaluate approximatively later */ + if (Integer(k_maxNValue).isLowerThan(n)) { + return this; } Integer result(1); - int clippedK = k.extractedInt(); // Authorized because k < k_maxNumberOfSteps - /* TODO: cap n and k -> if k or n too big, do not reduce to avoid too long - * computation. The permute coefficient will be evaluate approximatively - * later */ + int clippedK = k.extractedInt(); // Authorized because k < n < k_maxNValue for (int i = 0; i < clippedK; i++) { Integer factor = Integer::Subtraction(n, Integer(i)); result = Integer::Multiplication(result, factor); @@ -79,7 +78,7 @@ Complex * PermuteCoefficient::templatedEvaluate(Context& context, AngleUnit a T k = static_cast *>(kInput)->toScalar(); delete nInput; delete kInput; - if (isnan(n) || isnan(k) || n != std::round(n) || k != std::round(k) || n < 0.0f || k < 0.0f || k > k_maxNumberOfSteps) { + if (isnan(n) || isnan(k) || n != std::round(n) || k != std::round(k) || n < 0.0f || k < 0.0f) { return new Complex(Complex::Float(NAN)); } if (k > n) { @@ -88,6 +87,9 @@ Complex * PermuteCoefficient::templatedEvaluate(Context& context, AngleUnit a T result = 1; for (int i = (int)n-(int)k+1; i <= (int)n; i++) { result *= i; + if (isinf(result)) { + return new Complex(Complex::Float(result)); + } } return new Complex(Complex::Float(std::round(result))); } diff --git a/poincare/test/simplify_easy.cpp b/poincare/test/simplify_easy.cpp index 56fba0e6a..1f6c7d5fe 100644 --- a/poincare/test/simplify_easy.cpp +++ b/poincare/test/simplify_easy.cpp @@ -147,7 +147,7 @@ QUIZ_CASE(poincare_simplify_easy) { assert_parsed_expression_simplify_to("lcm(123,278)", "34194"); assert_parsed_expression_simplify_to("lcm(11,121)", "121"); assert_parsed_expression_simplify_to("root(4,3)", "4^(1/3)"); - assert_parsed_expression_simplify_to("permute(102,4)", "101989800"); + assert_parsed_expression_simplify_to("permute(99,4)", "90345024"); assert_parsed_expression_simplify_to("permute(20,-10)", "undef"); assert_parsed_expression_simplify_to("re(1/2)", "1/2");