Numworks Epsilon  1.4.1
Graphing Calculator Operating System
derivative.cpp
Go to the documentation of this file.
1 #include <poincare/derivative.h>
2 #include <poincare/symbol.h>
3 #include <poincare/complex.h>
5 #include <poincare/undefined.h>
6 #include <cmath>
7 extern "C" {
8 #include <assert.h>
9 #include <float.h>
10 }
11 
12 namespace Poincare {
13 
15  return Type::Derivative;
16 }
17 
19  Derivative * a = new Derivative(m_operands, true);
20  return a;
21 }
22 
23 int Derivative::polynomialDegree(char symbolName) const {
24  if (symbolName == 'x') {
25  if (operand(1)->polynomialDegree(symbolName) != 0) {
26  return -1;
27  }
28  return 0;
29  }
30  return Expression::polynomialDegree(symbolName);
31 }
32 
33 Expression * Derivative::shallowReduce(Context& context, AngleUnit angleUnit) {
34  Expression * e = Expression::shallowReduce(context, angleUnit);
35  if (e != this) {
36  return e;
37  }
38 #if MATRIX_EXACT_REDUCING
39  if (operand(0)->type() == Type::Matrix || operand(1)->type() == Type::Matrix) {
40  return replaceWith(new Undefined(), true);
41  }
42 #endif
43  // TODO: to be implemented diff(+) -> +diff() etc
44  return this;
45 }
46 
47 template<typename T>
48 Expression * Derivative::templatedApproximate(Context& context, AngleUnit angleUnit) const {
49  static T min = sizeof(T) == sizeof(double) ? DBL_MIN : FLT_MIN;
50  static T epsilon = sizeof(T) == sizeof(double) ? DBL_EPSILON : FLT_EPSILON;
51  VariableContext<T> xContext = VariableContext<T>('x', &context);
52  Symbol xSymbol('x');
53  Expression * xInput = operand(1)->approximate<T>(context, angleUnit);
54  T x = xInput->type() == Type::Complex ? static_cast<Complex<T> *>(xInput)->toScalar() : NAN;
55  delete xInput;
56  Complex<T> e = Complex<T>::Float(x);
57  xContext.setExpressionForSymbolName(&e, &xSymbol, xContext);
58  Expression * fInput = operand(0)->approximate<T>(xContext, angleUnit);
59  T functionValue = fInput->type() == Type::Complex ? static_cast<Complex<T> *>(fInput)->toScalar() : NAN;
60  delete fInput;
61 
62  // No complex/matrix version of Derivative
63  if (std::isnan(x) || std::isnan(functionValue)) {
64  return new Complex<T>(Complex<T>::Float(NAN));
65  }
66 
67  T error, result;
68  T h = k_minInitialRate;
69  do {
70  result = riddersApproximation(xContext, angleUnit, x, h, &error);
71  h /= 10.0;
72  } while ((std::fabs(error/result) > k_maxErrorRateOnApproximation || std::isnan(error)) && h >= epsilon);
73 
74  /* if the error is too big regarding the value, do not return the answer */
75  if (std::fabs(error/result) > k_maxErrorRateOnApproximation || std::isnan(error)) {
76  return new Complex<T>(Complex<T>::Float(NAN));
77  }
78  if (std::fabs(error) < min) {
79  return new Complex<T>(Complex<T>::Float(result));
80  }
81  error = std::pow((T)10, std::floor(std::log10(std::fabs(error)))+2);
82  return new Complex<T>(Complex<T>::Float(std::round(result/error)*error));
83 }
84 
85 template<typename T>
86 T Derivative::growthRateAroundAbscissa(T x, T h, VariableContext<T> xContext, AngleUnit angleUnit) const {
87  Symbol xSymbol('x');
88  Complex<T> e = Complex<T>::Float(x + h);
89  xContext.setExpressionForSymbolName(&e, &xSymbol, xContext);
90  Expression * fInput = operand(0)->approximate<T>(xContext, angleUnit);
91  T expressionPlus = fInput->type() == Type::Complex ? static_cast<Complex<T> *>(fInput)->toScalar() : NAN;
92  delete fInput;
93  e = Complex<T>::Float(x-h);
94  xContext.setExpressionForSymbolName(&e, &xSymbol, xContext);
95  fInput = operand(0)->approximate<T>(xContext, angleUnit);
96  T expressionMinus = fInput->type() == Type::Complex ? static_cast<Complex<T> *>(fInput)->toScalar() : NAN;
97  delete fInput;
98  return (expressionPlus - expressionMinus)/(2*h);
99 }
100 
101 template<typename T>
102 T Derivative::riddersApproximation(VariableContext<T> xContext, AngleUnit angleUnit, T x, T h, T * error) const {
103  /* Ridders' Algorithm
104  * Blibliography:
105  * - Ridders, C.J.F. 1982, Advances in Engineering Software, vol. 4, no. 2,
106  * pp. 75–76. */
107 
108  *error = sizeof(T) == sizeof(float) ? FLT_MAX : DBL_MAX;
109  // Initialize hh
110  assert(h != 0.0);
111  /* Make hh an exactly representable number */
112  volatile T temp = x+h;
113  T hh = temp - x;
114  /* a is matrix storing the function extrapolations for different stepsizes at
115  * different order */
116  T a[10][10];
117  for (int i = 0; i < 10; i++) {
118  for (int j = 0; j < 10; j++) {
119  a[i][j] = 1;
120  }
121  }
122  a[0][0] = growthRateAroundAbscissa(x, hh, xContext, angleUnit);
123  T ans = 0;
124  T errt = 0;
125  /* Loop on i: change the step size */
126  for (int i = 1; i < 10; i++) {
127  hh /= k_rateStepSize;
128  /* Make hh an exactly representable number */
129  volatile T temp = x+hh;
130  hh = temp - x;
131  a[0][i] = growthRateAroundAbscissa(x, hh, xContext, angleUnit);
132  T fac = k_rateStepSize*k_rateStepSize;
133  /* Loop on j: compute extrapolation for several orders */
134  for (int j = 1; j < 10; j++) {
135  a[j][i] = (a[j-1][i]*fac-a[j-1][i-1])/(fac-1);
136  fac = k_rateStepSize*k_rateStepSize*fac;
137  errt = std::fabs(a[j][i]-a[j-1][i]) > std::fabs(a[j][i]-a[j-1][i-1]) ? std::fabs(a[j][i]-a[j-1][i]) : std::fabs(a[j][i]-a[j-1][i-1]);
138  /* Update error and answer if error decreases */
139  if (errt < *error) {
140  *error = errt;
141  ans = a[j][i];
142  }
143  }
144  /* If higher extrapolation order significantly increases the error, return
145  * early */
146  if (std::fabs(a[i][i]-a[i-1][i-1]) > 2*(*error)) {
147  break;
148  }
149  }
150  return ans;
151 }
152 
153 }
154 
#define NAN
Definition: math.h:30
#define FLT_EPSILON
Definition: float.h:8
#define assert(e)
Definition: assert.h:9
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
friend class Symbol
Definition: expression.h:72
friend class Derivative
Definition: expression.h:39
#define FLT_MIN
Definition: float.h:7
#define fabs(x)
Definition: math.h:178
#define DBL_EPSILON
Definition: float.h:11
#define DBL_MAX
Definition: float.h:9
#define FLT_MAX
Definition: float.h:6
#define round(x)
Definition: math.h:192
#define pow(x, y)
Definition: math.h:190
const Expression * m_operands[T]
#define log10(x)
Definition: math.h:186
#define isnan(x)
Definition: math.h:43
Type type() const override
Definition: derivative.cpp:14
static Complex< T > Float(T x)
Definition: complex.cpp:23
Expression * clone() const override
Definition: derivative.cpp:18
#define floor(x)
Definition: math.h:179
const Expression * operand(int i) const
Definition: expression.cpp:78
#define DBL_MIN
Definition: float.h:10
virtual int polynomialDegree(char symbolName) const
Definition: expression.cpp:202
friend class Undefined
Definition: expression.h:17
int polynomialDegree(char symbolName) const override
Definition: derivative.cpp:23