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