1 /*
2     SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
3     SPDX-FileCopyrightText: 2003-2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
4     SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
5     SPDX-FileCopyrightText: 1995 Martin Bartlett
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "kcalc_core.h"
11 #include "kcalc_settings.h"
12 #include "kcalchistory.h"
13 
14 #include <QDebug>
15 
16 namespace
17 {
Deg2Rad(const KNumber & x)18 KNumber Deg2Rad(const KNumber &x)
19 {
20     return x * (KNumber::Pi() / KNumber(180));
21 }
22 
Gra2Rad(const KNumber & x)23 KNumber Gra2Rad(const KNumber &x)
24 {
25     return x * (KNumber::Pi() / KNumber(200));
26 }
27 
Rad2Deg(const KNumber & x)28 KNumber Rad2Deg(const KNumber &x)
29 {
30     return x * (KNumber(180) / KNumber::Pi());
31 }
32 
Rad2Gra(const KNumber & x)33 KNumber Rad2Gra(const KNumber &x)
34 {
35     return x * (KNumber(200) / KNumber::Pi());
36 }
37 
38 bool error_;
39 
ExecOr(const KNumber & left_op,const KNumber & right_op)40 KNumber ExecOr(const KNumber &left_op, const KNumber &right_op)
41 {
42     return left_op | right_op;
43 }
44 
ExecXor(const KNumber & left_op,const KNumber & right_op)45 KNumber ExecXor(const KNumber &left_op, const KNumber &right_op)
46 {
47     return left_op ^ right_op;
48 }
49 
ExecAnd(const KNumber & left_op,const KNumber & right_op)50 KNumber ExecAnd(const KNumber &left_op, const KNumber &right_op)
51 {
52     return left_op & right_op;
53 }
54 
ExecLsh(const KNumber & left_op,const KNumber & right_op)55 KNumber ExecLsh(const KNumber &left_op, const KNumber &right_op)
56 {
57     return left_op << right_op;
58 }
59 
ExecRsh(const KNumber & left_op,const KNumber & right_op)60 KNumber ExecRsh(const KNumber &left_op, const KNumber &right_op)
61 {
62     return left_op >> right_op;
63 }
64 
ExecAdd(const KNumber & left_op,const KNumber & right_op)65 KNumber ExecAdd(const KNumber &left_op, const KNumber &right_op)
66 {
67     return left_op + right_op;
68 }
69 
ExecSubtract(const KNumber & left_op,const KNumber & right_op)70 KNumber ExecSubtract(const KNumber &left_op, const KNumber &right_op)
71 {
72     return left_op - right_op;
73 }
74 
ExecMultiply(const KNumber & left_op,const KNumber & right_op)75 KNumber ExecMultiply(const KNumber &left_op, const KNumber &right_op)
76 {
77     return left_op * right_op;
78 }
79 
ExecDivide(const KNumber & left_op,const KNumber & right_op)80 KNumber ExecDivide(const KNumber &left_op, const KNumber &right_op)
81 {
82     return left_op / right_op;
83 }
84 
ExecMod(const KNumber & left_op,const KNumber & right_op)85 KNumber ExecMod(const KNumber &left_op, const KNumber &right_op)
86 {
87     return left_op % right_op;
88 }
89 
ExecIntDiv(const KNumber & left_op,const KNumber & right_op)90 KNumber ExecIntDiv(const KNumber &left_op, const KNumber &right_op)
91 {
92     return (left_op / right_op).integerPart();
93 }
94 
ExecBinom(const KNumber & left_op,const KNumber & right_op)95 KNumber ExecBinom(const KNumber &left_op, const KNumber &right_op)
96 {
97     return left_op.bin(right_op);
98 }
99 
ExecPower(const KNumber & left_op,const KNumber & right_op)100 KNumber ExecPower(const KNumber &left_op, const KNumber &right_op)
101 {
102     return left_op.pow(right_op);
103 }
104 
ExecPwrRoot(const KNumber & left_op,const KNumber & right_op)105 KNumber ExecPwrRoot(const KNumber &left_op, const KNumber &right_op)
106 {
107     return left_op.pow(KNumber::One / right_op);
108 }
109 
ExecAddP(const KNumber & left_op,const KNumber & right_op)110 KNumber ExecAddP(const KNumber &left_op, const KNumber &right_op)
111 {
112     return left_op * (KNumber::One + right_op / KNumber(100));
113 }
114 
ExecSubP(const KNumber & left_op,const KNumber & right_op)115 KNumber ExecSubP(const KNumber &left_op, const KNumber &right_op)
116 {
117     return left_op * (KNumber::One - right_op / KNumber(100));
118 }
119 
ExecMultiplyP(const KNumber & left_op,const KNumber & right_op)120 KNumber ExecMultiplyP(const KNumber &left_op, const KNumber &right_op)
121 {
122     return left_op * right_op / KNumber(100);
123 }
124 
ExecDivideP(const KNumber & left_op,const KNumber & right_op)125 KNumber ExecDivideP(const KNumber &left_op, const KNumber &right_op)
126 {
127     return left_op * KNumber(100) / right_op;
128 }
129 
130 // move a number into the interval [0,360) by adding multiples of 360
moveIntoDegInterval(const KNumber & num)131 KNumber moveIntoDegInterval(const KNumber &num)
132 {
133     KNumber tmp_num = num - (num / KNumber(360)).integerPart() * KNumber(360);
134     if (tmp_num < KNumber::Zero)
135         return tmp_num + KNumber(360);
136     return tmp_num;
137 }
138 
139 // move a number into the interval [0,400) by adding multiples of 400
moveIntoGradInterval(const KNumber & num)140 KNumber moveIntoGradInterval(const KNumber &num)
141 {
142     KNumber tmp_num = num - (num / KNumber(400)).integerPart() * KNumber(400);
143     if (tmp_num < KNumber::Zero)
144         return tmp_num + KNumber(400);
145     return tmp_num;
146 }
147 
148 typedef KNumber (*Arith)(const KNumber &, const KNumber &);
149 typedef KNumber (*Prcnt)(const KNumber &, const KNumber &);
150 
151 struct operator_data {
152     int precedence; // priority of operators in " enum Operation"
153     Arith arith_ptr;
154     Prcnt prcnt_ptr;
155 };
156 
157 // build precedence list
158 const struct operator_data Operator[] = {
159     {0, nullptr, nullptr}, // FUNC_EQUAL
160     {0, nullptr, nullptr}, // FUNC_PERCENT
161     {0, nullptr, nullptr}, // FUNC_BRACKET
162     {1, ExecOr, nullptr}, // FUNC_OR
163     {2, ExecXor, nullptr}, // FUNC_XOR
164     {3, ExecAnd, nullptr}, // FUNC_AND
165     {4, ExecLsh, nullptr}, // FUNC_LSH
166     {4, ExecRsh, nullptr}, // FUNC_RSH
167     {5, ExecAdd, ExecAddP}, // FUNC_ADD
168     {5, ExecSubtract, ExecSubP}, // FUNC_SUBTRACT
169     {6, ExecMultiply, ExecMultiplyP}, // FUNC_MULTIPLY
170     {6, ExecDivide, ExecDivideP}, // FUNC_DIVIDE
171     {6, ExecMod, nullptr}, // FUNC_MOD
172     {6, ExecIntDiv, nullptr}, // FUNC_INTDIV
173     {7, ExecBinom, nullptr}, // FUNC_BINOM
174     {7, ExecPower, nullptr}, // FUNC_POWER
175     {7, ExecPwrRoot, nullptr} // FUNC_PWR_ROOT
176 };
177 
178 }
179 
CalcEngine()180 CalcEngine::CalcEngine()
181     : only_update_operation_(false)
182     , percent_mode_(false)
183     , repeat_mode_(false)
184 {
185     last_number_ = KNumber::Zero;
186     error_ = false;
187     last_operation_ = FUNC_EQUAL;
188 }
189 
lastOutput(bool & error) const190 KNumber CalcEngine::lastOutput(bool &error) const
191 {
192     error = error_;
193     return last_number_;
194 }
195 
ArcCosDeg(const KNumber & input)196 void CalcEngine::ArcCosDeg(const KNumber &input)
197 {
198     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
199         last_number_ = KNumber::NaN;
200         return;
201     }
202 
203     if (input.type() == KNumber::TYPE_INTEGER) {
204         if (input == KNumber::One) {
205             last_number_ = KNumber::Zero;
206             return;
207         }
208         if (input == -KNumber::One) {
209             last_number_ = KNumber(180);
210             return;
211         }
212         if (input == KNumber::Zero) {
213             last_number_ = KNumber(90);
214             return;
215         }
216     }
217     last_number_ = Rad2Deg(input.acos());
218 }
219 
ArcCosRad(const KNumber & input)220 void CalcEngine::ArcCosRad(const KNumber &input)
221 {
222     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
223         last_number_ = KNumber::NaN;
224         return;
225     }
226     last_number_ = input.acos();
227 }
228 
ArcCosGrad(const KNumber & input)229 void CalcEngine::ArcCosGrad(const KNumber &input)
230 {
231     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
232         last_number_ = KNumber::NaN;
233         return;
234     }
235     if (input.type() == KNumber::TYPE_INTEGER) {
236         if (input == KNumber::One) {
237             last_number_ = KNumber::Zero;
238             return;
239         }
240         if (input == -KNumber::One) {
241             last_number_ = KNumber(200);
242             return;
243         }
244         if (input == KNumber::Zero) {
245             last_number_ = KNumber(100);
246             return;
247         }
248     }
249     last_number_ = Rad2Gra(input.acos());
250 }
251 
ArcSinDeg(const KNumber & input)252 void CalcEngine::ArcSinDeg(const KNumber &input)
253 {
254     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
255         last_number_ = KNumber::NaN;
256         return;
257     }
258     if (input.type() == KNumber::TYPE_INTEGER) {
259         if (input == KNumber::One) {
260             last_number_ = KNumber(90);
261             return;
262         }
263         if (input == -KNumber::One) {
264             last_number_ = KNumber(-90);
265             return;
266         }
267         if (input == KNumber::Zero) {
268             last_number_ = KNumber::Zero;
269             return;
270         }
271     }
272     last_number_ = Rad2Deg(input.asin());
273 }
274 
ArcSinRad(const KNumber & input)275 void CalcEngine::ArcSinRad(const KNumber &input)
276 {
277     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
278         last_number_ = KNumber::NaN;
279         return;
280     }
281     last_number_ = input.asin();
282 }
283 
ArcSinGrad(const KNumber & input)284 void CalcEngine::ArcSinGrad(const KNumber &input)
285 {
286     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
287         last_number_ = KNumber::NaN;
288         return;
289     }
290     if (input.type() == KNumber::TYPE_INTEGER) {
291         if (input == KNumber::One) {
292             last_number_ = KNumber(100);
293             return;
294         }
295         if (input == -KNumber::One) {
296             last_number_ = KNumber(-100);
297             return;
298         }
299         if (input == KNumber::Zero) {
300             last_number_ = KNumber::Zero;
301             return;
302         }
303     }
304     last_number_ = Rad2Gra(input.asin());
305 }
306 
ArcTangensDeg(const KNumber & input)307 void CalcEngine::ArcTangensDeg(const KNumber &input)
308 {
309     if (input.type() == KNumber::TYPE_ERROR) {
310         if (input == KNumber::NaN)
311             last_number_ = KNumber::NaN;
312         if (input == KNumber::PosInfinity)
313             last_number_ = KNumber(90);
314         if (input == KNumber::NegInfinity)
315             last_number_ = KNumber(-90);
316         return;
317     }
318 
319     last_number_ = Rad2Deg(input.atan());
320 }
321 
ArcTangensRad(const KNumber & input)322 void CalcEngine::ArcTangensRad(const KNumber &input)
323 {
324     if (input.type() == KNumber::TYPE_ERROR) {
325         if (input == KNumber::NaN)
326             last_number_ = KNumber::NaN;
327         if (input == KNumber::PosInfinity)
328             last_number_ = KNumber::Pi() / KNumber(2);
329         if (input == KNumber::NegInfinity)
330             last_number_ = -KNumber::Pi() / KNumber(2);
331         return;
332     }
333 
334     last_number_ = input.atan();
335 }
336 
ArcTangensGrad(const KNumber & input)337 void CalcEngine::ArcTangensGrad(const KNumber &input)
338 {
339     if (input.type() == KNumber::TYPE_ERROR) {
340         if (input == KNumber::NaN)
341             last_number_ = KNumber::NaN;
342         if (input == KNumber::PosInfinity)
343             last_number_ = KNumber(100);
344         if (input == KNumber::NegInfinity)
345             last_number_ = KNumber(-100);
346         return;
347     }
348 
349     last_number_ = Rad2Gra(input.atan());
350 }
351 
AreaCosHyp(const KNumber & input)352 void CalcEngine::AreaCosHyp(const KNumber &input)
353 {
354     if (input.type() == KNumber::TYPE_ERROR) {
355         if (input == KNumber::NaN)
356             last_number_ = KNumber::NaN;
357         if (input == KNumber::PosInfinity)
358             last_number_ = KNumber::PosInfinity;
359         if (input == KNumber::NegInfinity)
360             last_number_ = KNumber::NaN;
361         return;
362     }
363 
364     if (input < KNumber::One) {
365         last_number_ = KNumber::NaN;
366         return;
367     }
368     if (input == KNumber::One) {
369         last_number_ = KNumber::Zero;
370         return;
371     }
372     last_number_ = input.acosh();
373 }
374 
AreaSinHyp(const KNumber & input)375 void CalcEngine::AreaSinHyp(const KNumber &input)
376 {
377     if (input.type() == KNumber::TYPE_ERROR) {
378         if (input == KNumber::NaN)
379             last_number_ = KNumber::NaN;
380         if (input == KNumber::PosInfinity)
381             last_number_ = KNumber::PosInfinity;
382         if (input == KNumber::NegInfinity)
383             last_number_ = KNumber::NegInfinity;
384         return;
385     }
386 
387     if (input == KNumber::Zero) {
388         last_number_ = KNumber::Zero;
389         return;
390     }
391     last_number_ = input.asinh();
392 }
393 
AreaTangensHyp(const KNumber & input)394 void CalcEngine::AreaTangensHyp(const KNumber &input)
395 {
396     if (input.type() == KNumber::TYPE_ERROR) {
397         last_number_ = KNumber::NaN;
398         return;
399     }
400 
401     if (input < -KNumber::One || input > KNumber::One) {
402         last_number_ = KNumber::NaN;
403         return;
404     }
405     if (input == KNumber::One) {
406         last_number_ = KNumber::PosInfinity;
407         return;
408     }
409     if (input == -KNumber::One) {
410         last_number_ = KNumber::NegInfinity;
411         return;
412     }
413     last_number_ = input.atanh();
414 }
415 
Complement(const KNumber & input)416 void CalcEngine::Complement(const KNumber &input)
417 {
418     if (input.type() != KNumber::TYPE_INTEGER) {
419         last_number_ = KNumber::NaN;
420         return;
421     }
422 
423     last_number_ = ~input;
424 }
425 
CosDeg(const KNumber & input)426 void CalcEngine::CosDeg(const KNumber &input)
427 {
428     if (input.type() == KNumber::TYPE_ERROR) {
429         last_number_ = KNumber::NaN;
430         return;
431     }
432 
433     KNumber trunc_input = moveIntoDegInterval(input);
434 
435     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
436         KNumber mult = trunc_input / KNumber(90);
437         if (mult.type() == KNumber::TYPE_INTEGER) {
438             if (mult == KNumber::Zero)
439                 last_number_ = KNumber::One;
440             else if (mult == KNumber::One)
441                 last_number_ = KNumber::Zero;
442             else if (mult == KNumber(2))
443                 last_number_ = KNumber::NegOne;
444             else if (mult == KNumber(3))
445                 last_number_ = KNumber::Zero;
446             else
447                 qDebug() << "Something wrong in CalcEngine::CosDeg";
448             return;
449         }
450     }
451 
452     trunc_input = Deg2Rad(trunc_input);
453     last_number_ = trunc_input.cos();
454 }
455 
CosRad(const KNumber & input)456 void CalcEngine::CosRad(const KNumber &input)
457 {
458     if (input.type() == KNumber::TYPE_ERROR) {
459         last_number_ = KNumber::NaN;
460         return;
461     }
462 
463     last_number_ = input.cos();
464 }
465 
CosGrad(const KNumber & input)466 void CalcEngine::CosGrad(const KNumber &input)
467 {
468     if (input.type() == KNumber::TYPE_ERROR) {
469         last_number_ = KNumber::NaN;
470         return;
471     }
472     KNumber trunc_input = moveIntoGradInterval(input);
473     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
474         KNumber mult = trunc_input / KNumber(100);
475         if (mult.type() == KNumber::TYPE_INTEGER) {
476             if (mult == KNumber::Zero)
477                 last_number_ = KNumber::One;
478             else if (mult == KNumber::One)
479                 last_number_ = KNumber::Zero;
480             else if (mult == KNumber(2))
481                 last_number_ = KNumber::NegOne;
482             else if (mult == KNumber(3))
483                 last_number_ = KNumber::Zero;
484             else
485                 qDebug() << "Something wrong in CalcEngine::CosGrad";
486             return;
487         }
488     }
489     trunc_input = Gra2Rad(trunc_input);
490 
491     last_number_ = trunc_input.cos();
492 }
493 
CosHyp(const KNumber & input)494 void CalcEngine::CosHyp(const KNumber &input)
495 {
496     if (input.type() == KNumber::TYPE_ERROR) {
497         if (input == KNumber::NaN)
498             last_number_ = KNumber::NaN;
499         if (input == KNumber::PosInfinity)
500             last_number_ = KNumber::PosInfinity;
501         // YES, this should be *positive* infinity. We mimic the behavior of
502         // libc which says the following for cosh
503         //
504         // "If x is positive infinity or negative infinity, positive infinity is returned."
505         if (input == KNumber::NegInfinity)
506             last_number_ = KNumber::PosInfinity;
507         return;
508     }
509 
510     last_number_ = input.cosh();
511 }
512 
Cube(const KNumber & input)513 void CalcEngine::Cube(const KNumber &input)
514 {
515     last_number_ = input * input * input;
516 }
517 
CubeRoot(const KNumber & input)518 void CalcEngine::CubeRoot(const KNumber &input)
519 {
520     last_number_ = input.cbrt();
521 }
522 
Exp(const KNumber & input)523 void CalcEngine::Exp(const KNumber &input)
524 {
525     if (input.type() == KNumber::TYPE_ERROR) {
526         if (input == KNumber::NaN)
527             last_number_ = KNumber::NaN;
528         if (input == KNumber::PosInfinity)
529             last_number_ = KNumber::PosInfinity;
530         if (input == KNumber::NegInfinity)
531             last_number_ = KNumber::Zero;
532         return;
533     }
534     last_number_ = KNumber::Euler().pow(input);
535 }
536 
Exp10(const KNumber & input)537 void CalcEngine::Exp10(const KNumber &input)
538 {
539     if (input.type() == KNumber::TYPE_ERROR) {
540         if (input == KNumber::NaN)
541             last_number_ = KNumber::NaN;
542         if (input == KNumber::PosInfinity)
543             last_number_ = KNumber::PosInfinity;
544         if (input == KNumber::NegInfinity)
545             last_number_ = KNumber::Zero;
546         return;
547     }
548     last_number_ = KNumber(10).pow(input);
549 }
550 
Factorial(const KNumber & input)551 void CalcEngine::Factorial(const KNumber &input)
552 {
553     if (input == KNumber::PosInfinity)
554         return;
555     if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) {
556         error_ = true;
557         last_number_ = KNumber::NaN;
558         return;
559     }
560 
561     last_number_ = input.integerPart().factorial();
562 }
563 
Gamma(const KNumber & input)564 void CalcEngine::Gamma(const KNumber &input)
565 {
566     if (input == KNumber::PosInfinity)
567         return;
568     if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) {
569         error_ = true;
570         last_number_ = KNumber::NaN;
571         return;
572     }
573 
574     last_number_ = input.tgamma();
575 }
576 
InvertSign(const KNumber & input)577 void CalcEngine::InvertSign(const KNumber &input)
578 {
579     last_number_ = -input;
580 }
581 
Ln(const KNumber & input)582 void CalcEngine::Ln(const KNumber &input)
583 {
584     if (input < KNumber::Zero)
585         last_number_ = KNumber::NaN;
586     else if (input == KNumber::Zero)
587         last_number_ = KNumber::NegInfinity;
588     else if (input == KNumber::One)
589         last_number_ = KNumber::Zero;
590     else {
591         last_number_ = input.ln();
592     }
593 }
594 
Log10(const KNumber & input)595 void CalcEngine::Log10(const KNumber &input)
596 {
597     if (input < KNumber::Zero)
598         last_number_ = KNumber::NaN;
599     else if (input == KNumber::Zero)
600         last_number_ = KNumber::NegInfinity;
601     else if (input == KNumber::One)
602         last_number_ = KNumber::Zero;
603     else {
604         last_number_ = input.log10();
605     }
606 }
607 
ParenClose(KNumber input)608 void CalcEngine::ParenClose(KNumber input)
609 {
610     // evaluate stack until corresponding opening bracket
611     while (!stack_.isEmpty()) {
612         Node tmp_node = stack_.pop();
613         if (tmp_node.operation == FUNC_BRACKET)
614             break;
615         input = evalOperation(tmp_node.number, tmp_node.operation, input);
616     }
617     last_number_ = input;
618     return;
619 }
620 
ParenOpen(const KNumber & input)621 void CalcEngine::ParenOpen(const KNumber &input)
622 {
623     enterOperation(input, FUNC_BRACKET);
624 }
625 
Reciprocal(const KNumber & input)626 void CalcEngine::Reciprocal(const KNumber &input)
627 {
628     last_number_ = KNumber::One / input;
629 }
630 
SinDeg(const KNumber & input)631 void CalcEngine::SinDeg(const KNumber &input)
632 {
633     if (input.type() == KNumber::TYPE_ERROR) {
634         last_number_ = KNumber::NaN;
635         return;
636     }
637 
638     KNumber trunc_input = moveIntoDegInterval(input);
639     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
640         KNumber mult = trunc_input / KNumber(90);
641         if (mult.type() == KNumber::TYPE_INTEGER) {
642             if (mult == KNumber::Zero)
643                 last_number_ = KNumber::Zero;
644             else if (mult == KNumber::One)
645                 last_number_ = KNumber::One;
646             else if (mult == KNumber(2))
647                 last_number_ = KNumber::Zero;
648             else if (mult == KNumber(3))
649                 last_number_ = KNumber::NegOne;
650             else
651                 qDebug() << "Something wrong in CalcEngine::SinDeg";
652             return;
653         }
654     }
655     trunc_input = Deg2Rad(trunc_input);
656 
657     last_number_ = trunc_input.sin();
658 }
659 
SinRad(const KNumber & input)660 void CalcEngine::SinRad(const KNumber &input)
661 {
662     if (input.type() == KNumber::TYPE_ERROR) {
663         last_number_ = KNumber::NaN;
664         return;
665     }
666 
667     last_number_ = input.sin();
668 }
669 
SinGrad(const KNumber & input)670 void CalcEngine::SinGrad(const KNumber &input)
671 {
672     if (input.type() == KNumber::TYPE_ERROR) {
673         last_number_ = KNumber::NaN;
674         return;
675     }
676 
677     KNumber trunc_input = moveIntoGradInterval(input);
678     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
679         KNumber mult = trunc_input / KNumber(100);
680         if (mult.type() == KNumber::TYPE_INTEGER) {
681             if (mult == KNumber::Zero)
682                 last_number_ = KNumber::Zero;
683             else if (mult == KNumber::One)
684                 last_number_ = KNumber::One;
685             else if (mult == KNumber(2))
686                 last_number_ = KNumber::Zero;
687             else if (mult == KNumber(3))
688                 last_number_ = KNumber::NegOne;
689             else
690                 qDebug() << "Something wrong in CalcEngine::SinGrad";
691             return;
692         }
693     }
694 
695     trunc_input = Gra2Rad(trunc_input);
696 
697     last_number_ = trunc_input.sin();
698 }
699 
SinHyp(const KNumber & input)700 void CalcEngine::SinHyp(const KNumber &input)
701 {
702     if (input.type() == KNumber::TYPE_ERROR) {
703         if (input == KNumber::NaN)
704             last_number_ = KNumber::NaN;
705         if (input == KNumber::PosInfinity)
706             last_number_ = KNumber::PosInfinity;
707         if (input == KNumber::NegInfinity)
708             last_number_ = KNumber::NegInfinity;
709         return;
710     }
711 
712     last_number_ = input.sinh();
713 }
714 
Square(const KNumber & input)715 void CalcEngine::Square(const KNumber &input)
716 {
717     last_number_ = input * input;
718 }
719 
SquareRoot(const KNumber & input)720 void CalcEngine::SquareRoot(const KNumber &input)
721 {
722     last_number_ = input.sqrt();
723 }
724 
StatClearAll(const KNumber & input)725 void CalcEngine::StatClearAll(const KNumber &input)
726 {
727     Q_UNUSED(input);
728     stats.clearAll();
729 }
730 
StatCount(const KNumber & input)731 void CalcEngine::StatCount(const KNumber &input)
732 {
733     Q_UNUSED(input);
734     last_number_ = KNumber(stats.count());
735 }
736 
StatDataNew(const KNumber & input)737 void CalcEngine::StatDataNew(const KNumber &input)
738 {
739     stats.enterData(input);
740     last_number_ = KNumber(stats.count());
741 }
742 
StatDataDel(const KNumber & input)743 void CalcEngine::StatDataDel(const KNumber &input)
744 {
745     Q_UNUSED(input);
746     stats.clearLast();
747     last_number_ = KNumber(stats.count());
748 }
749 
StatMean(const KNumber & input)750 void CalcEngine::StatMean(const KNumber &input)
751 {
752     Q_UNUSED(input);
753     last_number_ = stats.mean();
754 
755     error_ = stats.error();
756 }
757 
StatMedian(const KNumber & input)758 void CalcEngine::StatMedian(const KNumber &input)
759 {
760     Q_UNUSED(input);
761     last_number_ = stats.median();
762 
763     error_ = stats.error();
764 }
765 
StatStdDeviation(const KNumber & input)766 void CalcEngine::StatStdDeviation(const KNumber &input)
767 {
768     Q_UNUSED(input);
769     last_number_ = stats.std();
770 
771     error_ = stats.error();
772 }
773 
StatStdSample(const KNumber & input)774 void CalcEngine::StatStdSample(const KNumber &input)
775 {
776     Q_UNUSED(input);
777     last_number_ = stats.sample_std();
778 
779     error_ = stats.error();
780 }
781 
StatSum(const KNumber & input)782 void CalcEngine::StatSum(const KNumber &input)
783 {
784     Q_UNUSED(input);
785     last_number_ = stats.sum();
786 }
787 
StatSumSquares(const KNumber & input)788 void CalcEngine::StatSumSquares(const KNumber &input)
789 {
790     Q_UNUSED(input);
791     last_number_ = stats.sum_of_squares();
792 
793     error_ = stats.error();
794 }
795 
TangensDeg(const KNumber & input)796 void CalcEngine::TangensDeg(const KNumber &input)
797 {
798     if (input.type() == KNumber::TYPE_ERROR) {
799         last_number_ = KNumber::NaN;
800         return;
801     }
802 
803     SinDeg(input);
804     KNumber arg1 = last_number_;
805     CosDeg(input);
806     KNumber arg2 = last_number_;
807 
808     last_number_ = arg1 / arg2;
809 }
810 
TangensRad(const KNumber & input)811 void CalcEngine::TangensRad(const KNumber &input)
812 {
813     if (input.type() == KNumber::TYPE_ERROR) {
814         last_number_ = KNumber::NaN;
815         return;
816     }
817 
818     SinRad(input);
819     KNumber arg1 = last_number_;
820     CosRad(input);
821     KNumber arg2 = last_number_;
822 
823     last_number_ = arg1 / arg2;
824 }
825 
TangensGrad(const KNumber & input)826 void CalcEngine::TangensGrad(const KNumber &input)
827 {
828     if (input.type() == KNumber::TYPE_ERROR) {
829         last_number_ = KNumber::NaN;
830         return;
831     }
832 
833     SinGrad(input);
834     KNumber arg1 = last_number_;
835     CosGrad(input);
836     KNumber arg2 = last_number_;
837 
838     last_number_ = arg1 / arg2;
839 }
840 
TangensHyp(const KNumber & input)841 void CalcEngine::TangensHyp(const KNumber &input)
842 {
843     if (input.type() == KNumber::TYPE_ERROR) {
844         if (input == KNumber::NaN)
845             last_number_ = KNumber::NaN;
846         if (input == KNumber::PosInfinity)
847             last_number_ = KNumber::One;
848         if (input == KNumber::NegInfinity)
849             last_number_ = KNumber::NegOne;
850         return;
851     }
852 
853     last_number_ = input.tanh();
854 }
855 
evalOperation(const KNumber & arg1,Operation operation,const KNumber & arg2)856 KNumber CalcEngine::evalOperation(const KNumber &arg1, Operation operation, const KNumber &arg2)
857 {
858     if (!percent_mode_ || Operator[operation].prcnt_ptr == nullptr) {
859         return (Operator[operation].arith_ptr)(arg1, arg2);
860     } else {
861         percent_mode_ = false;
862         return (Operator[operation].prcnt_ptr)(arg1, arg2);
863     }
864 }
865 
enterOperation(const KNumber & number,Operation func,Repeat allow_repeat)866 void CalcEngine::enterOperation(const KNumber &number, Operation func, Repeat allow_repeat)
867 {
868     Node tmp_node;
869 
870     if (func == FUNC_BRACKET) {
871         tmp_node.number = KNumber::Zero;
872         tmp_node.operation = FUNC_BRACKET;
873 
874         stack_.push(tmp_node);
875 
876         return;
877     }
878 
879     if (func == FUNC_PERCENT) {
880         percent_mode_ = true;
881     }
882 
883     tmp_node.number = number;
884     tmp_node.operation = func;
885 
886     if (KCalcSettings::repeatLastOperation()) {
887         if (func != FUNC_EQUAL && func != FUNC_PERCENT) {
888             last_operation_ = tmp_node.operation;
889             repeat_mode_ = false;
890         }
891 
892         if (func == FUNC_EQUAL || func == FUNC_PERCENT) {
893             if (!repeat_mode_) {
894                 repeat_mode_ = last_operation_ != FUNC_EQUAL;
895                 last_repeat_number_ = number;
896             } else if (allow_repeat == REPEAT_ALLOW) {
897                 Node repeat_node;
898                 repeat_node.operation = last_operation_;
899                 repeat_node.number = number;
900                 tmp_node.number = last_repeat_number_;
901                 stack_.push(repeat_node);
902             }
903         }
904     }
905 
906     if (getOnlyUpdateOperation() && !stack_.isEmpty() && !(func == FUNC_EQUAL || func == FUNC_PERCENT))
907         stack_.top().operation = func;
908     else
909         stack_.push(tmp_node);
910 
911     // The check for '=' or '%' is unnecessary; it is just a safety measure
912     if (!((func == FUNC_EQUAL) || (func == FUNC_PERCENT)))
913         setOnlyUpdateOperation(true);
914 
915     evalStack();
916 }
917 
evalStack()918 bool CalcEngine::evalStack()
919 {
920     // this should never happen
921     Q_ASSERT(!stack_.isEmpty());
922 
923     Node tmp_node = stack_.pop();
924 
925     while (!stack_.isEmpty()) {
926         Node tmp_node2 = stack_.pop();
927         if (Operator[tmp_node.operation].precedence <= Operator[tmp_node2.operation].precedence) {
928             if (tmp_node2.operation == FUNC_BRACKET)
929                 continue;
930             const KNumber tmp_result = evalOperation(tmp_node2.number, tmp_node2.operation, tmp_node.number);
931             tmp_node.number = tmp_result;
932         } else {
933             stack_.push(tmp_node2);
934             break;
935         }
936     }
937 
938     if (tmp_node.operation != FUNC_EQUAL && tmp_node.operation != FUNC_PERCENT)
939         stack_.push(tmp_node);
940 
941     last_number_ = tmp_node.number;
942     return true;
943 }
944 
Reset()945 void CalcEngine::Reset()
946 {
947     percent_mode_ = false;
948     repeat_mode_ = false;
949     last_operation_ = FUNC_EQUAL;
950     error_ = false;
951     last_number_ = KNumber::Zero;
952     only_update_operation_ = false;
953 
954     stack_.clear();
955 }
956 
setOnlyUpdateOperation(bool update)957 void CalcEngine::setOnlyUpdateOperation(bool update)
958 {
959     only_update_operation_ = update;
960 }
961 
getOnlyUpdateOperation() const962 bool CalcEngine::getOnlyUpdateOperation() const
963 {
964     return only_update_operation_;
965 }
966