[poincare] Cap binomial and permute coefficient reducing

Change-Id: Ib0c08a9788d77025e709d295bf05f30de50e9253
This commit is contained in:
Émilie Feral
2017-11-20 11:16:01 +01:00
parent d9897dd982
commit cb432e165e
5 changed files with 22 additions and 17 deletions

View File

@@ -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 {

View File

@@ -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());

View File

@@ -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<T>(Complex<T>::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<T>(Complex<T>::Float(result));
}
}
return new Complex<T>(Complex<T>::Float(std::round(result)));
}

View File

@@ -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<T> * PermuteCoefficient::templatedEvaluate(Context& context, AngleUnit a
T k = static_cast<Complex<T> *>(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<T>(Complex<T>::Float(NAN));
}
if (k > n) {
@@ -88,6 +87,9 @@ Complex<T> * 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<T>(Complex<T>::Float(result));
}
}
return new Complex<T>(Complex<T>::Float(std::round(result)));
}

View File

@@ -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");