Numworks Epsilon  1.4.1
Graphing Calculator Operating System
calculation.cpp
Go to the documentation of this file.
1 #include "calculation.h"
2 #include "calculation_store.h"
3 #include <string.h>
4 #include <cmath>
5 using namespace Poincare;
6 
7 namespace Calculation {
8 
10  m_inputText(),
11  m_exactOutputText(),
12  m_approximateOutputText(),
13  m_input(nullptr),
14  m_inputLayout(nullptr),
15  m_exactOutput(nullptr),
16  m_exactOutputLayout(nullptr),
17  m_approximateOutput(nullptr),
18  m_approximateOutputLayout(nullptr)
19 {
20 }
21 
22 Calculation::~Calculation() {
23  if (m_inputLayout != nullptr) {
24  delete m_inputLayout;
25  m_inputLayout = nullptr;
26  }
27  if (m_input != nullptr) {
28  delete m_input;
29  m_input = nullptr;
30  }
31  if (m_exactOutput != nullptr) {
32  delete m_exactOutput;
33  m_exactOutput = nullptr;
34  }
35  if (m_exactOutputLayout != nullptr) {
36  delete m_exactOutputLayout;
37  m_exactOutputLayout = nullptr;
38  }
39  if (m_approximateOutput != nullptr) {
40  delete m_approximateOutput;
41  m_approximateOutput = nullptr;
42  }
43  if (m_approximateOutputLayout != nullptr) {
44  delete m_approximateOutputLayout;
45  m_approximateOutputLayout = nullptr;
46  }
47 }
48 
49 Calculation& Calculation::operator=(const Calculation& other) {
50  const char * otherInputText = other.m_inputText;
51  const char * otherExactOutputText = other.m_exactOutputText;
52  const char * otherApproximateOutputText = other.m_approximateOutputText;
53  reset();
54  strlcpy(m_inputText, otherInputText, sizeof(m_inputText));
55  strlcpy(m_exactOutputText, otherExactOutputText, sizeof(m_exactOutputText));
56  strlcpy(m_approximateOutputText, otherApproximateOutputText, sizeof(m_approximateOutputText));
57  return *this;
58 }
59 
60 void Calculation::reset() {
61  m_inputText[0] = 0;
62  m_exactOutputText[0] = 0;
63  m_approximateOutputText[0] = 0;
64  tidy();
65 }
66 
67 void Calculation::setContent(const char * c, Context * context, Expression * ansExpression) {
68  reset();
69  m_input = Expression::parse(c);
70  Expression::ReplaceSymbolWithExpression(&m_input, Symbol::SpecialSymbols::Ans, ansExpression);
71  /* We do not store directly the text enter by the user but its serialization
72  * to be able to compare it to the exact ouput text. */
73  m_input->writeTextInBuffer(m_inputText, sizeof(m_inputText));
74  m_exactOutput = Expression::ParseAndSimplify(m_inputText, *context);
75  m_exactOutput->writeTextInBuffer(m_exactOutputText, sizeof(m_exactOutputText));
76  m_approximateOutput = m_exactOutput->approximate<double>(*context);
77  m_approximateOutput->writeTextInBuffer(m_approximateOutputText, sizeof(m_approximateOutputText));
78 }
79 
80 const char * Calculation::inputText() {
81  return m_inputText;
82 }
83 
84 const char * Calculation::exactOutputText() {
85  return m_exactOutputText;
86 }
87 
88 const char * Calculation::approximateOutputText() {
89  return m_approximateOutputText;
90 }
91 
92 Expression * Calculation::input() {
93  if (m_input == nullptr) {
94  m_input = Expression::parse(m_inputText);
95  }
96  return m_input;
97 }
98 
99 ExpressionLayout * Calculation::inputLayout() {
100  if (m_inputLayout == nullptr && input() != nullptr) {
101  m_inputLayout = input()->createLayout(PrintFloat::Mode::Decimal, Expression::ComplexFormat::Cartesian);
102  }
103  return m_inputLayout;
104 }
105 
106 bool Calculation::isEmpty() {
107  /* To test if a calculation is empty, we need to test either m_inputText or
108  * m_exactOutputText or m_approximateOutputText, the only three fields that
109  * are not lazy-loaded. We choose m_exactOutputText to consider that a
110  * calculation being added is still empty until the end of the method
111  * 'setContent'. Indeed, during 'setContent' method, 'ans' evaluation calls
112  * the evaluation of the last calculation only if the calculation being
113  * filled is not taken into account.*/
114  if (strlen(m_approximateOutputText) == 0) {
115  return true;
116  }
117  return false;
118 }
119 
120 void Calculation::tidy() {
121  if (m_input != nullptr) {
122  delete m_input;
123  }
124  m_input = nullptr;
125  if (m_inputLayout != nullptr) {
126  delete m_inputLayout;
127  }
128  m_inputLayout = nullptr;
129  if (m_exactOutput != nullptr) {
130  delete m_exactOutput;
131  }
132  m_exactOutput = nullptr;
133  if (m_exactOutputLayout != nullptr) {
134  delete m_exactOutputLayout;
135  }
136  m_exactOutputLayout = nullptr;
137  if (m_approximateOutput != nullptr) {
138  delete m_approximateOutput;
139  }
140  m_approximateOutput = nullptr;
141  if (m_approximateOutputLayout != nullptr) {
142  delete m_approximateOutputLayout;
143  }
144  m_approximateOutputLayout = nullptr;
145 }
146 
147 Expression * Calculation::exactOutput(Context * context) {
148  if (m_exactOutput == nullptr) {
149  /* To ensure that the expression 'm_exactOutput' is a simplified, we
150  * call 'ParseAndSimplify'. */
151  m_exactOutput = Expression::ParseAndSimplify(m_exactOutputText, *context);
152  }
153  return m_exactOutput;
154 }
155 
156 ExpressionLayout * Calculation::exactOutputLayout(Context * context) {
157  if (m_exactOutputLayout == nullptr && exactOutput(context) != nullptr) {
158  m_exactOutputLayout = exactOutput(context)->createLayout();
159  }
160  return m_exactOutputLayout;
161 }
162 
163 Expression * Calculation::approximateOutput(Context * context) {
164  if (m_approximateOutput == nullptr) {
165  /* To ensure that the expression 'm_output' is a matrix or a complex, we
166  * call 'evaluate'. */
167  Expression * exp = Expression::parse(m_approximateOutputText);
168  if (exp != nullptr) {
169  m_approximateOutput = exp->approximate<double>(*context);
170  delete exp;
171  } else {
172  m_approximateOutput = new Complex<double>(Complex<double>::Float(NAN));
173  }
174  }
175  return m_approximateOutput;
176 }
177 
178 ExpressionLayout * Calculation::approximateOutputLayout(Context * context) {
179  if (m_approximateOutputLayout == nullptr && approximateOutput(context) != nullptr) {
180  m_approximateOutputLayout = approximateOutput(context)->createLayout();
181  }
182  return m_approximateOutputLayout;
183 }
184 
185 bool Calculation::shouldDisplayApproximateOutput(Context * context) {
186  if (strcmp(m_exactOutputText, m_approximateOutputText) == 0) {
187  return true;
188  }
189  if (strcmp(m_exactOutputText, m_inputText) == 0) {
190  return true;
191  }
192  return input()->isApproximate(*context);
193 }
194 
195 bool Calculation::exactAndApproximateDisplayedOutputsAreEqual(Poincare::Context * context) {
196  char buffer[k_printedExpressionSize];
197  approximateOutput(context)->writeTextInBuffer(buffer, k_printedExpressionSize, Preferences::sharedPreferences()->numberOfSignificantDigits());
198  /* Warning: we cannot use directly the m_approximateOutputText but we have to
199  * re-serialize the approximateOutput because the number of stored
200  * significative numbers and the number of displayed significative numbers
201  * are not identical. (For example, 0.000025 might be displayed "0.00003"
202  * which requires in an approximative equal) */
203  Expression * approximateOutput = Expression::ParseAndSimplify(buffer, *context);
204  bool isEqual = approximateOutput->isIdenticalTo(exactOutput(context));
205  delete approximateOutput;
206  return isEqual;
207 }
208 
209 }
#define exp(x)
Definition: math.h:176
#define NAN
Definition: math.h:30
size_t strlcpy(char *dst, const char *src, size_t len)
Definition: strlcpy.c:3
constexpr Expression::ComplexFormat Cartesian
c(generic_all_nodes)
size_t strlen(const char *s)
Definition: strlen.c:3
bool isIdenticalTo(const Expression *e) const
Definition: expression.h:219
constexpr Event Ans
Definition: events.h:113
int strcmp(const char *s1, const char *s2)
Definition: strcmp.c:3