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

source code of kcalc/kcalc_core.cpp