Numworks Epsilon  1.4.1
Graphing Calculator Operating System
complex.cpp
Go to the documentation of this file.
1 #include <poincare/complex.h>
2 #include <poincare/undefined.h>
3 #include <poincare/decimal.h>
4 #include <poincare/addition.h>
6 #include <poincare/symbol.h>
7 #include <poincare/ieee754.h>
8 extern "C" {
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <float.h>
13 }
14 #include <cmath>
15 #include "layout/string_layout.h"
17 #include <ion.h>
18 #include <stdio.h>
19 
20 namespace Poincare {
21 
22 template<typename T>
24  return Complex(x,0);
25 }
26 
27 template<typename T>
29  return Complex(a,b);
30 }
31 
32 template<typename T>
34  // If the radius is 0, theta may be undefined but shouldn't be able to affect the result.
35  if (r == 0) {
36  return Complex(0,0);
37  }
38  T c = std::cos(th);
39  T s = std::sin(th);
40  /* Cheat: see comment on cosine.cpp.
41  * Sine and cosine openbsd immplementationd are numerical approximation.
42  * We though want to avoid evaluating e^(i*pi) to -1+1E-17i. We thus round
43  * cosine and sine results to 0 if they are negligible compared to the
44  * argument th. */
45  c = th != 0 && std::fabs(c/th) <= Expression::epsilon<T>() ? 0 : c;
46  s = th != 0 && std::fabs(s/th) <= Expression::epsilon<T>() ? 0 : s;
47  return Complex(r*c,r*s);
48 }
49 
50 template<typename T>
52  m_a = other.m_a;
53  m_b = other.m_b;
54 }
55 
56 template<typename T>
58  m_a = other.m_a;
59  m_b = other.m_b;
60  return *this;
61 }
62 
63 template<typename T>
64 static inline T privateFloatSetSign(T f, bool negative) {
65  if (negative) {
66  return -f;
67  }
68  return f;
69 }
70 
71 template<typename T>
72 T digitsToFloat(const char * digits, int length) {
73  if (digits == nullptr) {
74  return 0;
75  }
76  T result = 0;
77  const char * digit = digits;
78  for (int i = 0; i < length; i++) {
79  result = 10 * result;
80  result += *digit-'0';
81  digit++;
82  }
83  return result;
84 }
85 
86 template<typename T>
87 Complex<T>::Complex(const char * integralPart, int integralPartLength, bool integralNegative,
88  const char * fractionalPart, int fractionalPartLength,
89  const char * exponent, int exponentLength, bool exponentNegative) {
90  T i = digitsToFloat<T>(integralPart, integralPartLength);
91  T j = digitsToFloat<T>(fractionalPart, fractionalPartLength);
92  T l = privateFloatSetSign<T>(digitsToFloat<T>(exponent, exponentLength), exponentNegative);
93 
94  m_a = privateFloatSetSign((i + j*std::pow(10, -std::ceil((T)fractionalPartLength)))* std::pow(10, l), integralNegative);
95  m_b = 0;
96 }
97 
98 template <class T>
99 T Complex<T>::a() const {
100  return m_a;
101 }
102 
103 template <class T>
104 T Complex<T>::b() const {
105  return m_b;
106 }
107 
108 template <class T>
109 T Complex<T>::r() const {
110  // We want to avoid a^2 and b^2 which could both easily overflow.
111  // min, max = minmax(abs(a), abs(b)) (*minmax returns both arguments sorted*)
112  // abs(a + bi) == sqrt(a^2 + b^2)
113  // == sqrt(abs(a)^2 + abs(b)^2)
114  // == sqrt(min^2 + max^2)
115  // == sqrt((min^2 + max^2) * max^2/max^2)
116  // == sqrt((min^2 + max^2) / max^2)*sqrt(max^2)
117  // == sqrt(min^2/max^2 + 1) * max
118  // == sqrt((min/max)^2 + 1) * max
119  // min >= 0 &&
120  // max >= 0 &&
121  // min <= max => min/max <= 1
122  // => (min/max)^2 <= 1
123  // => (min/max)^2 + 1 <= 2
124  // => sqrt((min/max)^2 + 1) <= sqrt(2)
125  // So the calculation is guaranteed to not overflow until the final multiply.
126  // If (min/max)^2 underflows then min doesn't contribute anything significant
127  // compared to max, and the formula reduces to simply max as it should.
128  // We do need to be careful about the case where a == 0 && b == 0 which would
129  // cause a division by zero.
130  T min = std::fabs(m_a);
131  if (m_b == 0) {
132  return min;
133  }
134  T max = std::fabs(m_b);
135  if (max < min) {
136  T temp = min;
137  min = max;
138  max = temp;
139  }
140  T temp = min/max;
141  return std::sqrt(temp*temp + 1) * max;
142 }
143 
144 template <class T>
145 T Complex<T>::th() const {
146  T result = std::atan(m_b/m_a) + M_PI;
147  if (m_a >= 0) {
148  T a = m_a == 0 ? 0 : m_a;
149  result = std::atan(m_b/a);
150  }
151  if (result > M_PI + FLT_EPSILON) {
152  result = result - 2*M_PI;
153  }
154  return result;
155 }
156 
157 template <class T>
159  return Cartesian(m_a, -m_b);
160 }
161 
162 template<typename T>
165 }
166 
167 template <class T>
169  return new Complex<T>(*this);
170 }
171 
172 template<typename T>
174  if (m_b != 0) {
175  return NAN;
176  }
177  return m_a;
178 }
179 
180 template <class T>
181 int Complex<T>::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const {
182  return convertComplexToText(buffer, bufferSize, numberOfSignificantDigits, Preferences::sharedPreferences()->displayMode(), Preferences::sharedPreferences()->complexFormat(), Ion::Charset::MultiplicationSign);
183 }
184 
185 template <class T>
187  switch (e->type()) {
188  case Type::Addition:
189  return m_a < 0.0 || (m_a == 0.0 && m_b < 0.0);
190  case Type::Subtraction:
192  case Type::Opposite:
193  return m_a < 0.0 || m_b < 0.0 || (m_a != 0.0 && m_b != 0.0);
194  case Type::Factorial:
195  case Type::Power:
196  case Type::Division:
197  return m_a < 0.0 || m_b != 0.0;
198  default:
199  return false;
200  }
201 }
202 
203 
204 
205 template <class T>
206 Complex<T>::Complex(T a, T b) :
207  m_a(a),
208  m_b(b)
209 {
210 }
211 
212 template <class T>
213 ExpressionLayout * Complex<T>::privateCreateLayout(PrintFloat::Mode floatDisplayMode, Expression::ComplexFormat complexFormat) const {
214  assert(floatDisplayMode != PrintFloat::Mode::Default);
215  if (complexFormat == Expression::ComplexFormat::Polar) {
216  return createPolarLayout(floatDisplayMode);
217  }
218  return createCartesianLayout(floatDisplayMode);
219 }
220 
221 template <class T>
222 Expression * Complex<T>::CreateDecimal(T f) {
223  if (std::isnan(f) || std::isinf(f)) {
224  return new Undefined();
225  }
226  int e = IEEE754<T>::exponentBase10(f);
227  int64_t mantissaf = f * std::pow((T)10, -e+PrintFloat::k_numberOfStoredSignificantDigits+1);
228  return new Decimal(Integer(mantissaf), e);
229 }
230 
231 template <class T>
232 Expression * Complex<T>::shallowReduce(Context & context, AngleUnit angleUnit) {
233  Expression * a = CreateDecimal(m_a);
234  Expression * b = CreateDecimal(m_b);
235  Multiplication * m = new Multiplication(new Symbol(Ion::Charset::IComplex), b, false);
236  Addition * add = new Addition(a, m, false);
237  a->shallowReduce(context, angleUnit);
238  b->shallowReduce(context, angleUnit);
239  m->shallowReduce(context, angleUnit);
240  return replaceWith(add, true)->shallowReduce(context, angleUnit);
241 }
242 
243 template<typename T>
244 template<typename U>
245 Complex<U> * Complex<T>::templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const {
246  return new Complex<U>(Complex<U>::Cartesian((U)m_a, (U)m_b));
247 }
248 
249 template <class T>
250 int Complex<T>::convertComplexToText(char * buffer, int bufferSize, int numberOfSignificantDigits, PrintFloat::Mode displayMode, Expression::ComplexFormat complexFormat, char multiplicationSpecialChar) const {
251  assert(displayMode != PrintFloat::Mode::Default);
252  int numberOfChars = 0;
253  if (std::isnan(m_a) || std::isnan(m_b) || std::isinf(m_a) || std::isinf(m_b)) {
254  return PrintFloat::convertFloatToText<T>(NAN, buffer, bufferSize, numberOfSignificantDigits, displayMode);
255  }
256  if (complexFormat == Expression::ComplexFormat::Polar) {
257  if (r() != 1 || th() == 0) {
258  numberOfChars = PrintFloat::convertFloatToText<T>(r(), buffer, bufferSize, numberOfSignificantDigits, displayMode);
259  if (r() != 0 && th() != 0 && bufferSize > numberOfChars+1) {
260  buffer[numberOfChars++] = multiplicationSpecialChar;
261  // Ensure that the string is null terminated even if buffer size is to small
262  buffer[numberOfChars] = 0;
263  }
264  }
265  if (r() != 0 && th() != 0) {
266  if (bufferSize > numberOfChars+3) {
267  buffer[numberOfChars++] = Ion::Charset::Exponential;
268  buffer[numberOfChars++] = '^';
269  buffer[numberOfChars++] = '(';
270  // Ensure that the string is null terminated even if buffer size is to small
271  buffer[numberOfChars] = 0;
272  }
273  numberOfChars += PrintFloat::convertFloatToText<T>(th(), buffer+numberOfChars, bufferSize-numberOfChars, numberOfSignificantDigits, displayMode);
274  if (bufferSize > numberOfChars+3) {
275  buffer[numberOfChars++] = multiplicationSpecialChar;
276  buffer[numberOfChars++] = Ion::Charset::IComplex;
277  buffer[numberOfChars++] = ')';
278  buffer[numberOfChars] = 0;
279  }
280  }
281  return numberOfChars;
282  }
283 
284  if (m_a != 0 || m_b == 0) {
285  numberOfChars = PrintFloat::convertFloatToText<T>(m_a, buffer, bufferSize, numberOfSignificantDigits, displayMode);
286  if (m_b > 0 && !std::isnan(m_b) && bufferSize > numberOfChars+1) {
287  buffer[numberOfChars++] = '+';
288  // Ensure that the string is null terminated even if buffer size is to small
289  buffer[numberOfChars] = 0;
290  }
291  }
292  if (m_b != 1 && m_b != -1 && m_b != 0) {
293  numberOfChars += PrintFloat::convertFloatToText<T>(m_b, buffer+numberOfChars, bufferSize-numberOfChars, numberOfSignificantDigits, displayMode);
294  buffer[numberOfChars++] = multiplicationSpecialChar;
295  }
296  if (m_b == -1 && bufferSize > numberOfChars+1) {
297  buffer[numberOfChars++] = '-';
298  }
299  if (m_b != 0 && bufferSize > numberOfChars+1) {
300  buffer[numberOfChars++] = Ion::Charset::IComplex;
301  buffer[numberOfChars] = 0;
302  }
303  return numberOfChars;
304 }
305 
306 template <class T>
307 ExpressionLayout * Complex<T>::createPolarLayout(PrintFloat::Mode floatDisplayMode) const {
308  char bufferBase[PrintFloat::k_maxFloatBufferLength+2];
309  int numberOfCharInBase = 0;
310  char bufferSuperscript[PrintFloat::k_maxFloatBufferLength+2];
311  int numberOfCharInSuperscript = 0;
312 
313  if (std::isnan(r()) || (std::isnan(th()) && r() != 0)) {
314  numberOfCharInBase = PrintFloat::convertFloatToText<T>(NAN, bufferBase, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode);
315  return new StringLayout(bufferBase, numberOfCharInBase);
316  }
317  if (r() != 1 || th() == 0) {
318  numberOfCharInBase = PrintFloat::convertFloatToText<T>(r(), bufferBase, PrintFloat::k_maxFloatBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode);
319  if (r() != 0 && th() != 0) {
320  bufferBase[numberOfCharInBase++] = Ion::Charset::MiddleDot;
321  }
322  }
323  if (r() != 0 && th() != 0) {
324  bufferBase[numberOfCharInBase++] = Ion::Charset::Exponential;
325  bufferBase[numberOfCharInBase] = 0;
326  }
327 
328  if (r() != 0 && th() != 0) {
329  numberOfCharInSuperscript = PrintFloat::convertFloatToText<T>(th(), bufferSuperscript, PrintFloat::k_maxFloatBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode);
330  bufferSuperscript[numberOfCharInSuperscript++] = Ion::Charset::MiddleDot;
331  bufferSuperscript[numberOfCharInSuperscript++] = Ion::Charset::IComplex;
332  bufferSuperscript[numberOfCharInSuperscript] = 0;
333  }
334  if (numberOfCharInSuperscript == 0) {
335  return new StringLayout(bufferBase, numberOfCharInBase);
336  }
337  return new BaselineRelativeLayout(new StringLayout(bufferBase, numberOfCharInBase), new StringLayout(bufferSuperscript, numberOfCharInSuperscript), BaselineRelativeLayout::Type::Superscript);
338 }
339 
340 template <class T>
341 ExpressionLayout * Complex<T>::createCartesianLayout(PrintFloat::Mode floatDisplayMode) const {
342  char buffer[PrintFloat::k_maxComplexBufferLength];
343  int numberOfChars = convertComplexToText(buffer, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode, Expression::ComplexFormat::Cartesian, Ion::Charset::MiddleDot);
344  return new StringLayout(buffer, numberOfChars);
345 }
346 
347 template class Complex<float>;
348 template class Complex<double>;
349 template Complex<double>* Complex<double>::templatedApproximate<double>(Context&, Expression::AngleUnit) const;
350 template Complex<float>* Complex<double>::templatedApproximate<float>(Context&, Expression::AngleUnit) const;
351 template Complex<double>* Complex<float>::templatedApproximate<double>(Context&, Expression::AngleUnit) const;
352 template Complex<float>* Complex<float>::templatedApproximate<float>(Context&, Expression::AngleUnit) const;
353 
354 }
355 
T th() const
Definition: complex.cpp:145
Expression::Type type() const override
Definition: complex.cpp:163
#define NAN
Definition: math.h:30
static Preferences * sharedPreferences()
Definition: preferences.cpp:14
T toScalar() const
Definition: complex.cpp:173
constexpr Event Power
Definition: events.h:83
static Complex< T > Cartesian(T a, T b)
Definition: complex.cpp:28
#define FLT_EPSILON
Definition: float.h:8
#define assert(e)
Definition: assert.h:9
#define isinf(x)
Definition: math.h:44
#define M_PI
Definition: math.h:17
int writeTextInBuffer(char *buffer, int bufferSize, int numberOfSignificantDigits=PrintFloat::k_numberOfStoredSignificantDigits) const override
Definition: complex.cpp:181
#define U()
Definition: events.cpp:25
#define T(x)
Definition: events.cpp:26
T a() const
Definition: complex.cpp:99
#define atan(x)
Definition: math.h:167
static Complex< T > Polar(T r, T theta)
Definition: complex.cpp:33
constexpr Expression::ComplexFormat Cartesian
#define fabs(x)
Definition: math.h:178
c(generic_all_nodes)
constexpr Event Division
Definition: events.h:102
#define sin(x)
Definition: math.h:194
Complex< T > * clone() const override
Definition: complex.cpp:168
Complex & operator=(const Complex &other)
Definition: complex.cpp:57
#define pow(x, y)
Definition: math.h:190
#define cos(x)
Definition: math.h:172
Complex< T > conjugate() const
Definition: complex.cpp:158
#define ceil(x)
Definition: math.h:170
#define isnan(x)
Definition: math.h:43
static Complex< T > Float(T x)
Definition: complex.cpp:23
constexpr Event Multiplication
Definition: events.h:101
signed long long int64_t
Definition: stdint.h:12
bool needParenthesisWithParent(const Expression *e) const override
Definition: complex.cpp:186
constexpr Expression::ComplexFormat Polar
#define sqrt(x)
Definition: math.h:196
T digitsToFloat(const char *digits, int length)
Definition: complex.cpp:72
virtual Type type() const =0