Numworks Epsilon  1.4.1
Graphing Calculator Operating System
binomial_coefficient.cpp
Go to the documentation of this file.
2 #include <poincare/undefined.h>
3 #include <poincare/complex.h>
4 #include <poincare/rational.h>
6 #include "layout/grid_layout.h"
7 
8 extern "C" {
9 #include <stdlib.h>
10 #include <assert.h>
11 }
12 #include <cmath>
13 
14 namespace Poincare {
15 
18 }
19 
22  return b;
23 }
24 
25 Expression * BinomialCoefficient::shallowReduce(Context& context, AngleUnit angleUnit) {
26  Expression * e = Expression::shallowReduce(context, angleUnit);
27  if (e != this) {
28  return e;
29  }
30  Expression * op0 = editableOperand(0);
31  Expression * op1 = editableOperand(1);
32 #if MATRIX_EXACT_REDUCING
33  if (op0->type() == Type::Matrix || op1->type() == Type::Matrix) {
34  return replaceWith(new Undefined(), true);
35  }
36 #endif
37  if (op0->type() == Type::Rational) {
38  Rational * r0 = static_cast<Rational *>(op0);
39  if (!r0->denominator().isOne() || r0->numerator().isNegative()) {
40  return replaceWith(new Undefined(), true);
41  }
42  }
43  if (op1->type() == Type::Rational) {
44  Rational * r1 = static_cast<Rational *>(op1);
45  if (!r1->denominator().isOne() || r1->numerator().isNegative()) {
46  return replaceWith(new Undefined(), true);
47  }
48  }
49  if (op0->type() != Type::Rational || op1->type() != Type::Rational) {
50  return this;
51  }
52  Rational * r0 = static_cast<Rational *>(op0);
53  Rational * r1 = static_cast<Rational *>(op1);
54 
55  Integer n = r0->numerator();
56  Integer k = r1->numerator();
57  if (n.isLowerThan(k)) {
58  return replaceWith(new Undefined(), true);
59  }
60  /* if n is too big, we do not reduce to avoid too long computation.
61  * The binomial coefficient will be evaluate approximatively later */
62  if (Integer(k_maxNValue).isLowerThan(n)) {
63  return this;
64  }
65  Rational result(1);
66  Integer kBis = Integer::Subtraction(n, k);
67  k = kBis.isLowerThan(k) ? kBis : k;
68  int clippedK = k.extractedInt(); // Authorized because k < n < k_maxNValue
69  for (int i = 0; i < clippedK; i++) {
70  Rational factor = Rational(Integer::Subtraction(n, Integer(i)), Integer::Subtraction(k, Integer(i)));
71  result = Rational::Multiplication(result, factor);
72  }
73  return replaceWith(new Rational(result), true);
74 }
75 
76 ExpressionLayout * BinomialCoefficient::privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const {
77  assert(floatDisplayMode != PrintFloat::Mode::Default);
78  assert(complexFormat != ComplexFormat::Default);
79  ExpressionLayout * childrenLayouts[2];
80  childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat);
81  childrenLayouts[1] = operand(1)->createLayout(floatDisplayMode, complexFormat);
82  return new ParenthesisLayout(new GridLayout(childrenLayouts, 2, 1));
83 }
84 
85 template<typename T>
86 Expression * BinomialCoefficient::templatedApproximate(Context& context, AngleUnit angleUnit) const {
87  Expression * nInput = operand(0)->approximate<T>(context, angleUnit);
88  Expression * kInput = operand(1)->approximate<T>(context, angleUnit);
89  if (nInput->type() != Type::Complex || kInput->type() != Type::Complex) {
90  return new Complex<T>(Complex<T>::Float(NAN));
91  }
92  T n = static_cast<Complex<T> *>(nInput)->toScalar();
93  T k = static_cast<Complex<T> *>(kInput)->toScalar();
94  delete nInput;
95  delete kInput;
96  return new Complex<T>(Complex<T>::Float(compute(k, n)));
97 }
98 
99 
100 template<typename T>
102  k = k > (n-k) ? n-k : k;
103  if (std::isnan(n) || std::isnan(k) || n != std::round(n) || k != std::round(k) || k > n || k < 0 || n < 0) {
104  return NAN;
105  }
106  T result = 1;
107  for (int i = 0; i < k; i++) {
108  result *= (n-(T)i)/(k-(T)i);
109  if (std::isinf(result) || std::isnan(result)) {
110  return result;
111  }
112  }
113  return std::round(result);
114 }
115 
116 template double BinomialCoefficient::compute(double k, double n);
117 template float BinomialCoefficient::compute(float k, float n);
118 
119 }
#define NAN
Definition: math.h:30
#define assert(e)
Definition: assert.h:9
#define isinf(x)
Definition: math.h:44
friend class Multiplication
Definition: rational.h:12
Expression * replaceWith(Expression *newOperand, bool deleteAfterReplace=true)
Definition: expression.cpp:85
Expression * approximate(Context &context, AngleUnit angleUnit=AngleUnit::Default) const
Definition: expression.cpp:338
#define T(x)
Definition: events.cpp:26
Expression * editableOperand(int i)
Definition: expression.h:176
friend class Rational
Definition: expression.h:18
Expression * clone() const override
#define round(x)
Definition: math.h:192
const Expression * m_operands[T]
friend class BinomialCoefficient
Definition: expression.h:34
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode=PrintFloat::Mode::Default, ComplexFormat complexFormat=ComplexFormat::Default) const
Definition: expression.cpp:244
#define isnan(x)
Definition: math.h:43
static Complex< T > Float(T x)
Definition: complex.cpp:23
static Integer Subtraction(const Integer &i, const Integer &j)
Definition: integer.cpp:236
const Expression * operand(int i) const
Definition: expression.cpp:78
friend class Undefined
Definition: expression.h:17