Numworks Epsilon  1.4.1
Graphing Calculator Operating System
decimal.cpp
Go to the documentation of this file.
1 #include <poincare/decimal.h>
2 #include <poincare/complex.h>
3 #include <poincare/rational.h>
4 #include <poincare/opposite.h>
5 #include <assert.h>
6 #include <ion.h>
7 #include <cmath>
8 extern "C" {
9 #include <assert.h>
10 }
11 
12 #include "layout/string_layout.h"
13 
14 namespace Poincare {
15 
16 int Decimal::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) {
17  int base = 10;
18  int exp = 0;
19  for (int i = 0; i < exponentLength; i++) {
20  exp *= base;
21  exp += *exponent-'0';
22  exponent++;
23  }
24  if (exponentNegative) {
25  exp = -exp;
26  }
27  const char * integralPartEnd = integralPart + integralPartLength;
28  if (integralPart != nullptr) {
29  while (*integralPart == '0' && integralPart < integralPartEnd) {
30  integralPart++;
31  }
32  }
33  exp += integralPartEnd-integralPart-1;
34  if (integralPart == integralPartEnd) {
35  const char * fractionalPartEnd = fractionalPart + fractionalPartLength;
36  if (fractionalPart != nullptr) {
37  while (*fractionalPart == '0' && fractionalPart < fractionalPartEnd) {
38  fractionalPart++;
39  exp--;
40  }
41  }
42  if (fractionalPart == fractionalPartEnd) {
43  exp += fractionalPartLength+1;
44  }
45  }
46  return exp;
47 }
48 
50  if (i.isZero()) {
51  return;
52  }
53  Integer base = Integer(10);
55  while (d.remainder.isZero()) {
56  i = d.quotient;
57  d = Integer::Division(i, base);
58  }
59 }
60 
61 Integer Decimal::mantissa(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, bool negative) {
62  Integer zero = Integer(0);
63  Integer base = Integer(10);
64  Integer numerator = Integer(integralPart, negative);
65  for (int i = 0; i < fractionalPartLength; i++) {
66  numerator = Integer::Multiplication(numerator, base);
67  numerator = Integer::Addition(numerator, Integer(*fractionalPart-'0'));
68  fractionalPart++;
69  }
70  removeZeroAtTheEnd(numerator);
71  return numerator;
72 }
73 
74 Decimal::Decimal(Integer mantissa, int exponent) :
75  m_mantissa(mantissa),
76  m_exponent(exponent)
77 {
78 }
79 
80 Decimal::Decimal(double f) {
81  double logBase10 = f != 0 ? std::log10(std::fabs(f)) : 0;
82  int exponentInBase10 = std::floor(logBase10);
83  /* Correct the exponent in base 10: sometines the exact log10 of f is 6.999999
84  * but is stored as 7 in hardware. We catch these cases here. */
85  if (f != 0 && logBase10 == (int)logBase10 && std::fabs(f) < std::pow(10, logBase10)) {
86  exponentInBase10--;
87  }
88  double m = f*std::pow(10, (double)-exponentInBase10); // TODO: hangle exponentInBase10 is too big! mantissa is nan
89  m = m * std::pow(10, (double)(k_doublePrecision-1));
90  int64_t integerMantissa = std::round(m);
91  /* If m > 999999999999999.5, the mantissa stored will be 1 (as we keep only
92  * 15 significative numbers from double. In that case, the exponent must be
93  * increment as well. */
94  if (m >= k_biggestMantissaFromDouble+0.5) {
95  exponentInBase10++;
96  }
97  m_mantissa = Integer(integerMantissa);
98  removeZeroAtTheEnd(m_mantissa);
99  m_exponent = exponentInBase10;
100 }
101 
103  return Type::Decimal;
104 }
105 
107  return new Decimal(m_mantissa, m_exponent);
108 }
109 
110 template<typename T> Expression * Decimal::templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const {
111  T m = m_mantissa.approximate<T>();
112  int numberOfDigits = numberOfDigitsInMantissaWithoutSign();
113  return new Complex<T>(Complex<T>::Float(m*std::pow((T)10.0, (T)(m_exponent-numberOfDigits+1))));
114 }
115 
116 int Decimal::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const {
117  if (bufferSize == 0) {
118  return -1;
119  }
120  buffer[bufferSize-1] = 0;
121  int currentChar = 0;
122  if (currentChar >= bufferSize-1) { return bufferSize-1; }
123  if (m_mantissa.isZero()) {
124  buffer[currentChar++] = '0';
125  buffer[currentChar] = 0;
126  return currentChar;
127  }
128  char tempBuffer[200];
129  int mantissaLength = m_mantissa.writeTextInBuffer(tempBuffer, 200);
130  if (strcmp(tempBuffer, "undef") == 0) {
131  strlcpy(buffer, tempBuffer, bufferSize);
132  return mantissaLength;
133  }
134  int nbOfDigitsInMantissaWithoutSign = numberOfDigitsInMantissaWithoutSign();
135  int numberOfRequiredDigits = nbOfDigitsInMantissaWithoutSign > m_exponent ? nbOfDigitsInMantissaWithoutSign : m_exponent;
136  numberOfRequiredDigits = m_exponent < 0 ? 1+nbOfDigitsInMantissaWithoutSign-m_exponent : numberOfRequiredDigits;
137  /* Case 0: the number would be too long if we print it as a natural decimal */
138  if (numberOfRequiredDigits > k_maxLength) {
139  if (nbOfDigitsInMantissaWithoutSign == 1) {
140  currentChar += strlcpy(buffer, tempBuffer, bufferSize);
141  } else {
142  currentChar++;
143  if (currentChar >= bufferSize-1) { return bufferSize-1; }
144  currentChar += strlcpy(buffer+currentChar, tempBuffer, bufferSize-currentChar);
145  int decimalMarkerPosition = 1;
146  if (buffer[1] == '-') {
147  decimalMarkerPosition++;
148  buffer[0] = buffer[1];
149  }
150  buffer[decimalMarkerPosition-1] = buffer[decimalMarkerPosition];
151  buffer[decimalMarkerPosition] = '.';
152  }
153  if (m_exponent == 0) {
154  return currentChar;
155  }
156  if (currentChar >= bufferSize-1) { return bufferSize-1; }
157  buffer[currentChar++] = Ion::Charset::Exponent;
158  currentChar += Integer(m_exponent).writeTextInBuffer(buffer+currentChar, bufferSize-currentChar);
159  return currentChar;
160  }
161  /* Case 2: Print a natural decimal number */
162  int deltaCharMantissa = m_exponent < 0 ? -m_exponent+1 : 0;
163  strlcpy(buffer+deltaCharMantissa, tempBuffer, bufferSize-deltaCharMantissa);
164  if (m_mantissa.isNegative()) {
165  buffer[currentChar++] = '-';
166  }
167  if (m_exponent < 0) {
168  for (int i = 0; i <= -m_exponent; i++) {
169  if (currentChar >= bufferSize-1) { return bufferSize-1; }
170  if (i == 1) {
171  buffer[currentChar++] = '.';
172  continue;
173  }
174  buffer[currentChar++] = '0';
175  }
176  }
177  /* If mantissa is negative, m_mantissa.writeTextInBuffer is going to add an
178  * unwanted '-' in place of the temp char. We store it to replace it back
179  * after calling m_mantissa.writeTextInBuffer. */
180  char tempChar = 0;
181  int tempCharPosition = 0;
182  if (m_mantissa.isNegative()) {
183  currentChar--;
184  tempChar = buffer[currentChar];
185  tempCharPosition = currentChar;
186  }
187  currentChar += mantissaLength;
188  if (m_mantissa.isNegative()) { // replace the temp char back
189  buffer[tempCharPosition] = tempChar;
190  }
191  int currentExponent = m_mantissa.isNegative() ? currentChar-2 : currentChar-1;
192  if (m_exponent >= 0 && m_exponent < currentExponent) {
193  if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
194  int decimalMarkerPosition = m_mantissa.isNegative() ? m_exponent +1 : m_exponent;
195  for (int i = currentChar-1; i > decimalMarkerPosition; i--) {
196  buffer[i+1] = buffer[i];
197  }
198  buffer[decimalMarkerPosition+1] = '.';
199  currentChar++;
200  }
201  if (m_exponent >= 0 && m_exponent > currentExponent) {
202  int decimalMarkerPosition = m_mantissa.isNegative() ? m_exponent+1 : m_exponent;
203  for (int i = currentChar-1; i < decimalMarkerPosition; i++) {
204  if (currentChar+1 >= bufferSize-1) { return bufferSize-1; }
205  buffer[currentChar++] = '0';
206  }
207  }
208  buffer[currentChar] = 0;
209  return currentChar;
210 }
211 
212 bool Decimal::needParenthesisWithParent(const Expression * e) const {
213  if (sign() == Sign::Positive) {
214  return false;
215  }
217  return e->isOfType(types, 7);
218 }
219 
220 ExpressionLayout * Decimal::privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const {
221  char buffer[255];
222  int numberOfChars = writeTextInBuffer(buffer, 255);
223  return new StringLayout(buffer, numberOfChars);
224 }
225 
226 Expression * Decimal::shallowReduce(Context& context, AngleUnit angleUnit) {
227  Expression * e = Expression::shallowReduce(context, angleUnit);
228  if (e != this) {
229  return e;
230  }
231  // Do not reduce decimal to rational if the exponent is too big or too small.
232  if (m_exponent > k_maxDoubleExponent || m_exponent < -k_maxDoubleExponent) {
233  return this; // TODO: return new Infinite() ? new Rational(0) ?
234  }
235  int numberOfDigits = numberOfDigitsInMantissaWithoutSign();
236  Integer numerator = m_mantissa;
237  Integer denominator = Integer(1);
238  if (m_exponent >= numberOfDigits-1) {
239  numerator = Integer::Multiplication(m_mantissa, Integer::Power(Integer(10), Integer(m_exponent-numberOfDigits+1)));
240  } else {
241  denominator = Integer::Power(Integer(10), Integer(numberOfDigits-1-m_exponent));
242  }
243  return replaceWith(new Rational(numerator, denominator), true);
244 }
245 
246 Expression * Decimal::shallowBeautify(Context & context, AngleUnit angleUnit) {
247  if (m_mantissa.isNegative()) {
248  m_mantissa.setNegative(false);
249  Opposite * o = new Opposite(this, true);
250  return replaceWith(o, true);
251  }
252  return this;
253 }
254 
255 int Decimal::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const {
256  assert(e->type() == Type::Decimal);
257  const Decimal * other = static_cast<const Decimal *>(e);
258  if (sign() == Sign::Negative && other->sign() == Sign::Positive) {
259  return -1;
260  }
261  if (sign() == Sign::Positive && other->sign() == Sign::Negative) {
262  return 1;
263  }
264  assert(sign() == other->sign());
265  int unsignedComparison = 0;
266  if (exponent() < other->exponent()) {
267  unsignedComparison = -1;
268  } else if (exponent() > other->exponent()) {
269  unsignedComparison = 1;
270  } else {
271  assert(exponent() == other->exponent());
272  unsignedComparison = Integer::NaturalOrder(mantissa(), other->mantissa());
273  }
274  return ((int)sign())*unsignedComparison;
275 }
276 
277 int Decimal::numberOfDigitsInMantissaWithoutSign() const {
278  int numberOfDigits = 1;
279  Integer mantissaCopy = m_mantissa;
280  mantissaCopy.setNegative(false);
281  IntegerDivision d = Integer::Division(mantissaCopy, Integer(10));
282  while (!d.quotient.isZero()) {
283  mantissaCopy = d.quotient;
284  d = Integer::Division(mantissaCopy, Integer(10));
285  numberOfDigits++;
286  }
287  return numberOfDigits;
288 }
289 
290 }
#define exp(x)
Definition: math.h:176
T approximate() const
Definition: integer.cpp:479
static Integer Power(const Integer &i, const Integer &j)
Definition: integer.cpp:313
bool isZero() const
Definition: integer.h:72
#define assert(e)
Definition: assert.h:9
int writeTextInBuffer(char *buffer, int bufferSize) const
Definition: integer.cpp:545
Expression * replaceWith(Expression *newOperand, bool deleteAfterReplace=true)
Definition: expression.cpp:85
int writeTextInBuffer(char *buffer, int bufferSize, int numberOfSignificantDigits=PrintFloat::k_numberOfStoredSignificantDigits) const override
Definition: decimal.cpp:116
#define T(x)
Definition: events.cpp:26
size_t strlcpy(char *dst, const char *src, size_t len)
Definition: strlcpy.c:3
#define fabs(x)
Definition: math.h:178
void removeZeroAtTheEnd(Integer &i)
Definition: decimal.cpp:49
int exponent() const
Definition: decimal.h:20
friend class Rational
Definition: expression.h:18
void setNegative(bool negative)
Definition: integer.cpp:203
#define round(x)
Definition: math.h:192
friend class Opposite
Definition: expression.h:62
#define pow(x, y)
Definition: math.h:190
static Integer Addition(const Integer &i, const Integer &j)
Definition: integer.cpp:232
bool isNegative() const
Definition: integer.h:43
Decimal(Integer mantissa, int exponent)
Definition: decimal.cpp:74
#define log10(x)
Definition: math.h:186
static int NaturalOrder(const Integer &i, const Integer &j)
Definition: integer.cpp:212
static Complex< T > Float(T x)
Definition: complex.cpp:23
Sign sign() const override
Definition: decimal.h:26
Type type() const override
Definition: decimal.cpp:102
signed long long int64_t
Definition: stdint.h:12
int strcmp(const char *s1, const char *s2)
Definition: strcmp.c:3
#define floor(x)
Definition: math.h:179
static Integer Multiplication(const Integer &i, const Integer &j)
Definition: integer.cpp:240
static IntegerDivision Division(const Integer &numerator, const Integer &denominator)
Definition: integer.cpp:281
Integer mantissa() const
Definition: decimal.h:21
Expression * clone() const override
Definition: decimal.cpp:106