File indexing completed on 2021-12-21 14:36:20

0001 /*
0002     SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
0003     SPDX-FileCopyrightText: 2003-2005 Klaus Niederkrueger <kniederk@math.uni-koeln.de>
0004     SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
0005     SPDX-FileCopyrightText: 1995 Martin Bartlett
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "kcalc_core.h"
0011 #include "kcalc_settings.h"
0012 #include "kcalchistory.h"
0013 
0014 #include <QDebug>
0015 
0016 namespace
0017 {
0018 KNumber Deg2Rad(const KNumber &x)
0019 {
0020     return x * (KNumber::Pi() / KNumber(180));
0021 }
0022 
0023 KNumber Gra2Rad(const KNumber &x)
0024 {
0025     return x * (KNumber::Pi() / KNumber(200));
0026 }
0027 
0028 KNumber Rad2Deg(const KNumber &x)
0029 {
0030     return x * (KNumber(180) / KNumber::Pi());
0031 }
0032 
0033 KNumber Rad2Gra(const KNumber &x)
0034 {
0035     return x * (KNumber(200) / KNumber::Pi());
0036 }
0037 
0038 bool error_;
0039 
0040 KNumber ExecOr(const KNumber &left_op, const KNumber &right_op)
0041 {
0042     return left_op | right_op;
0043 }
0044 
0045 KNumber ExecXor(const KNumber &left_op, const KNumber &right_op)
0046 {
0047     return left_op ^ right_op;
0048 }
0049 
0050 KNumber ExecAnd(const KNumber &left_op, const KNumber &right_op)
0051 {
0052     return left_op & right_op;
0053 }
0054 
0055 KNumber ExecLsh(const KNumber &left_op, const KNumber &right_op)
0056 {
0057     return left_op << right_op;
0058 }
0059 
0060 KNumber ExecRsh(const KNumber &left_op, const KNumber &right_op)
0061 {
0062     return left_op >> right_op;
0063 }
0064 
0065 KNumber ExecAdd(const KNumber &left_op, const KNumber &right_op)
0066 {
0067     return left_op + right_op;
0068 }
0069 
0070 KNumber ExecSubtract(const KNumber &left_op, const KNumber &right_op)
0071 {
0072     return left_op - right_op;
0073 }
0074 
0075 KNumber ExecMultiply(const KNumber &left_op, const KNumber &right_op)
0076 {
0077     return left_op * right_op;
0078 }
0079 
0080 KNumber ExecDivide(const KNumber &left_op, const KNumber &right_op)
0081 {
0082     return left_op / right_op;
0083 }
0084 
0085 KNumber ExecMod(const KNumber &left_op, const KNumber &right_op)
0086 {
0087     return left_op % right_op;
0088 }
0089 
0090 KNumber ExecIntDiv(const KNumber &left_op, const KNumber &right_op)
0091 {
0092     return (left_op / right_op).integerPart();
0093 }
0094 
0095 KNumber ExecBinom(const KNumber &left_op, const KNumber &right_op)
0096 {
0097     return left_op.bin(right_op);
0098 }
0099 
0100 KNumber ExecPower(const KNumber &left_op, const KNumber &right_op)
0101 {
0102     return left_op.pow(right_op);
0103 }
0104 
0105 KNumber ExecPwrRoot(const KNumber &left_op, const KNumber &right_op)
0106 {
0107     return left_op.pow(KNumber::One / right_op);
0108 }
0109 
0110 KNumber ExecAddP(const KNumber &left_op, const KNumber &right_op)
0111 {
0112     return left_op * (KNumber::One + right_op / KNumber(100));
0113 }
0114 
0115 KNumber ExecSubP(const KNumber &left_op, const KNumber &right_op)
0116 {
0117     return left_op * (KNumber::One - right_op / KNumber(100));
0118 }
0119 
0120 KNumber ExecMultiplyP(const KNumber &left_op, const KNumber &right_op)
0121 {
0122     return left_op * right_op / KNumber(100);
0123 }
0124 
0125 KNumber ExecDivideP(const KNumber &left_op, const KNumber &right_op)
0126 {
0127     return left_op * KNumber(100) / right_op;
0128 }
0129 
0130 // move a number into the interval [0,360) by adding multiples of 360
0131 KNumber moveIntoDegInterval(const KNumber &num)
0132 {
0133     KNumber tmp_num = num - (num / KNumber(360)).integerPart() * KNumber(360);
0134     if (tmp_num < KNumber::Zero)
0135         return tmp_num + KNumber(360);
0136     return tmp_num;
0137 }
0138 
0139 // move a number into the interval [0,400) by adding multiples of 400
0140 KNumber moveIntoGradInterval(const KNumber &num)
0141 {
0142     KNumber tmp_num = num - (num / KNumber(400)).integerPart() * KNumber(400);
0143     if (tmp_num < KNumber::Zero)
0144         return tmp_num + KNumber(400);
0145     return tmp_num;
0146 }
0147 
0148 typedef KNumber (*Arith)(const KNumber &, const KNumber &);
0149 typedef KNumber (*Prcnt)(const KNumber &, const KNumber &);
0150 
0151 struct operator_data {
0152     int precedence; // priority of operators in " enum Operation"
0153     Arith arith_ptr;
0154     Prcnt prcnt_ptr;
0155 };
0156 
0157 // build precedence list
0158 const struct operator_data Operator[] = {
0159     {0, nullptr, nullptr}, // FUNC_EQUAL
0160     {0, nullptr, nullptr}, // FUNC_PERCENT
0161     {0, nullptr, nullptr}, // FUNC_BRACKET
0162     {1, ExecOr, nullptr}, // FUNC_OR
0163     {2, ExecXor, nullptr}, // FUNC_XOR
0164     {3, ExecAnd, nullptr}, // FUNC_AND
0165     {4, ExecLsh, nullptr}, // FUNC_LSH
0166     {4, ExecRsh, nullptr}, // FUNC_RSH
0167     {5, ExecAdd, ExecAddP}, // FUNC_ADD
0168     {5, ExecSubtract, ExecSubP}, // FUNC_SUBTRACT
0169     {6, ExecMultiply, ExecMultiplyP}, // FUNC_MULTIPLY
0170     {6, ExecDivide, ExecDivideP}, // FUNC_DIVIDE
0171     {6, ExecMod, nullptr}, // FUNC_MOD
0172     {6, ExecIntDiv, nullptr}, // FUNC_INTDIV
0173     {7, ExecBinom, nullptr}, // FUNC_BINOM
0174     {7, ExecPower, nullptr}, // FUNC_POWER
0175     {7, ExecPwrRoot, nullptr} // FUNC_PWR_ROOT
0176 };
0177 
0178 }
0179 
0180 CalcEngine::CalcEngine()
0181     : only_update_operation_(false)
0182     , percent_mode_(false)
0183     , repeat_mode_(false)
0184 {
0185     last_number_ = KNumber::Zero;
0186     error_ = false;
0187     last_operation_ = FUNC_EQUAL;
0188 }
0189 
0190 KNumber CalcEngine::lastOutput(bool &error) const
0191 {
0192     error = error_;
0193     return last_number_;
0194 }
0195 
0196 void CalcEngine::ArcCosDeg(const KNumber &input)
0197 {
0198     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0199         last_number_ = KNumber::NaN;
0200         return;
0201     }
0202 
0203     if (input.type() == KNumber::TYPE_INTEGER) {
0204         if (input == KNumber::One) {
0205             last_number_ = KNumber::Zero;
0206             return;
0207         }
0208         if (input == -KNumber::One) {
0209             last_number_ = KNumber(180);
0210             return;
0211         }
0212         if (input == KNumber::Zero) {
0213             last_number_ = KNumber(90);
0214             return;
0215         }
0216     }
0217     last_number_ = Rad2Deg(input.acos());
0218 }
0219 
0220 void CalcEngine::ArcCosRad(const KNumber &input)
0221 {
0222     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0223         last_number_ = KNumber::NaN;
0224         return;
0225     }
0226     last_number_ = input.acos();
0227 }
0228 
0229 void CalcEngine::ArcCosGrad(const KNumber &input)
0230 {
0231     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0232         last_number_ = KNumber::NaN;
0233         return;
0234     }
0235     if (input.type() == KNumber::TYPE_INTEGER) {
0236         if (input == KNumber::One) {
0237             last_number_ = KNumber::Zero;
0238             return;
0239         }
0240         if (input == -KNumber::One) {
0241             last_number_ = KNumber(200);
0242             return;
0243         }
0244         if (input == KNumber::Zero) {
0245             last_number_ = KNumber(100);
0246             return;
0247         }
0248     }
0249     last_number_ = Rad2Gra(input.acos());
0250 }
0251 
0252 void CalcEngine::ArcSinDeg(const KNumber &input)
0253 {
0254     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0255         last_number_ = KNumber::NaN;
0256         return;
0257     }
0258     if (input.type() == KNumber::TYPE_INTEGER) {
0259         if (input == KNumber::One) {
0260             last_number_ = KNumber(90);
0261             return;
0262         }
0263         if (input == -KNumber::One) {
0264             last_number_ = KNumber(-90);
0265             return;
0266         }
0267         if (input == KNumber::Zero) {
0268             last_number_ = KNumber::Zero;
0269             return;
0270         }
0271     }
0272     last_number_ = Rad2Deg(input.asin());
0273 }
0274 
0275 void CalcEngine::ArcSinRad(const KNumber &input)
0276 {
0277     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0278         last_number_ = KNumber::NaN;
0279         return;
0280     }
0281     last_number_ = input.asin();
0282 }
0283 
0284 void CalcEngine::ArcSinGrad(const KNumber &input)
0285 {
0286     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0287         last_number_ = KNumber::NaN;
0288         return;
0289     }
0290     if (input.type() == KNumber::TYPE_INTEGER) {
0291         if (input == KNumber::One) {
0292             last_number_ = KNumber(100);
0293             return;
0294         }
0295         if (input == -KNumber::One) {
0296             last_number_ = KNumber(-100);
0297             return;
0298         }
0299         if (input == KNumber::Zero) {
0300             last_number_ = KNumber::Zero;
0301             return;
0302         }
0303     }
0304     last_number_ = Rad2Gra(input.asin());
0305 }
0306 
0307 void CalcEngine::ArcTangensDeg(const KNumber &input)
0308 {
0309     if (input.type() == KNumber::TYPE_ERROR) {
0310         if (input == KNumber::NaN)
0311             last_number_ = KNumber::NaN;
0312         if (input == KNumber::PosInfinity)
0313             last_number_ = KNumber(90);
0314         if (input == KNumber::NegInfinity)
0315             last_number_ = KNumber(-90);
0316         return;
0317     }
0318 
0319     last_number_ = Rad2Deg(input.atan());
0320 }
0321 
0322 void CalcEngine::ArcTangensRad(const KNumber &input)
0323 {
0324     if (input.type() == KNumber::TYPE_ERROR) {
0325         if (input == KNumber::NaN)
0326             last_number_ = KNumber::NaN;
0327         if (input == KNumber::PosInfinity)
0328             last_number_ = KNumber::Pi() / KNumber(2);
0329         if (input == KNumber::NegInfinity)
0330             last_number_ = -KNumber::Pi() / KNumber(2);
0331         return;
0332     }
0333 
0334     last_number_ = input.atan();
0335 }
0336 
0337 void CalcEngine::ArcTangensGrad(const KNumber &input)
0338 {
0339     if (input.type() == KNumber::TYPE_ERROR) {
0340         if (input == KNumber::NaN)
0341             last_number_ = KNumber::NaN;
0342         if (input == KNumber::PosInfinity)
0343             last_number_ = KNumber(100);
0344         if (input == KNumber::NegInfinity)
0345             last_number_ = KNumber(-100);
0346         return;
0347     }
0348 
0349     last_number_ = Rad2Gra(input.atan());
0350 }
0351 
0352 void CalcEngine::AreaCosHyp(const KNumber &input)
0353 {
0354     if (input.type() == KNumber::TYPE_ERROR) {
0355         if (input == KNumber::NaN)
0356             last_number_ = KNumber::NaN;
0357         if (input == KNumber::PosInfinity)
0358             last_number_ = KNumber::PosInfinity;
0359         if (input == KNumber::NegInfinity)
0360             last_number_ = KNumber::NaN;
0361         return;
0362     }
0363 
0364     if (input < KNumber::One) {
0365         last_number_ = KNumber::NaN;
0366         return;
0367     }
0368     if (input == KNumber::One) {
0369         last_number_ = KNumber::Zero;
0370         return;
0371     }
0372     last_number_ = input.acosh();
0373 }
0374 
0375 void CalcEngine::AreaSinHyp(const KNumber &input)
0376 {
0377     if (input.type() == KNumber::TYPE_ERROR) {
0378         if (input == KNumber::NaN)
0379             last_number_ = KNumber::NaN;
0380         if (input == KNumber::PosInfinity)
0381             last_number_ = KNumber::PosInfinity;
0382         if (input == KNumber::NegInfinity)
0383             last_number_ = KNumber::NegInfinity;
0384         return;
0385     }
0386 
0387     if (input == KNumber::Zero) {
0388         last_number_ = KNumber::Zero;
0389         return;
0390     }
0391     last_number_ = input.asinh();
0392 }
0393 
0394 void CalcEngine::AreaTangensHyp(const KNumber &input)
0395 {
0396     if (input.type() == KNumber::TYPE_ERROR) {
0397         last_number_ = KNumber::NaN;
0398         return;
0399     }
0400 
0401     if (input < -KNumber::One || input > KNumber::One) {
0402         last_number_ = KNumber::NaN;
0403         return;
0404     }
0405     if (input == KNumber::One) {
0406         last_number_ = KNumber::PosInfinity;
0407         return;
0408     }
0409     if (input == -KNumber::One) {
0410         last_number_ = KNumber::NegInfinity;
0411         return;
0412     }
0413     last_number_ = input.atanh();
0414 }
0415 
0416 void CalcEngine::Complement(const KNumber &input)
0417 {
0418     if (input.type() != KNumber::TYPE_INTEGER) {
0419         last_number_ = KNumber::NaN;
0420         return;
0421     }
0422 
0423     last_number_ = ~input;
0424 }
0425 
0426 void CalcEngine::CosDeg(const KNumber &input)
0427 {
0428     if (input.type() == KNumber::TYPE_ERROR) {
0429         last_number_ = KNumber::NaN;
0430         return;
0431     }
0432 
0433     KNumber trunc_input = moveIntoDegInterval(input);
0434 
0435     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0436         KNumber mult = trunc_input / KNumber(90);
0437         if (mult.type() == KNumber::TYPE_INTEGER) {
0438             if (mult == KNumber::Zero)
0439                 last_number_ = KNumber::One;
0440             else if (mult == KNumber::One)
0441                 last_number_ = KNumber::Zero;
0442             else if (mult == KNumber(2))
0443                 last_number_ = KNumber::NegOne;
0444             else if (mult == KNumber(3))
0445                 last_number_ = KNumber::Zero;
0446             else
0447                 qDebug() << "Something wrong in CalcEngine::CosDeg";
0448             return;
0449         }
0450     }
0451 
0452     trunc_input = Deg2Rad(trunc_input);
0453     last_number_ = trunc_input.cos();
0454 }
0455 
0456 void CalcEngine::CosRad(const KNumber &input)
0457 {
0458     if (input.type() == KNumber::TYPE_ERROR) {
0459         last_number_ = KNumber::NaN;
0460         return;
0461     }
0462 
0463     last_number_ = input.cos();
0464 }
0465 
0466 void CalcEngine::CosGrad(const KNumber &input)
0467 {
0468     if (input.type() == KNumber::TYPE_ERROR) {
0469         last_number_ = KNumber::NaN;
0470         return;
0471     }
0472     KNumber trunc_input = moveIntoGradInterval(input);
0473     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0474         KNumber mult = trunc_input / KNumber(100);
0475         if (mult.type() == KNumber::TYPE_INTEGER) {
0476             if (mult == KNumber::Zero)
0477                 last_number_ = KNumber::One;
0478             else if (mult == KNumber::One)
0479                 last_number_ = KNumber::Zero;
0480             else if (mult == KNumber(2))
0481                 last_number_ = KNumber::NegOne;
0482             else if (mult == KNumber(3))
0483                 last_number_ = KNumber::Zero;
0484             else
0485                 qDebug() << "Something wrong in CalcEngine::CosGrad";
0486             return;
0487         }
0488     }
0489     trunc_input = Gra2Rad(trunc_input);
0490 
0491     last_number_ = trunc_input.cos();
0492 }
0493 
0494 void CalcEngine::CosHyp(const KNumber &input)
0495 {
0496     if (input.type() == KNumber::TYPE_ERROR) {
0497         if (input == KNumber::NaN)
0498             last_number_ = KNumber::NaN;
0499         if (input == KNumber::PosInfinity)
0500             last_number_ = KNumber::PosInfinity;
0501         // YES, this should be *positive* infinity. We mimic the behavior of
0502         // libc which says the following for cosh
0503         //
0504         // "If x is positive infinity or negative infinity, positive infinity is returned."
0505         if (input == KNumber::NegInfinity)
0506             last_number_ = KNumber::PosInfinity;
0507         return;
0508     }
0509 
0510     last_number_ = input.cosh();
0511 }
0512 
0513 void CalcEngine::Cube(const KNumber &input)
0514 {
0515     last_number_ = input * input * input;
0516 }
0517 
0518 void CalcEngine::CubeRoot(const KNumber &input)
0519 {
0520     last_number_ = input.cbrt();
0521 }
0522 
0523 void CalcEngine::Exp(const KNumber &input)
0524 {
0525     if (input.type() == KNumber::TYPE_ERROR) {
0526         if (input == KNumber::NaN)
0527             last_number_ = KNumber::NaN;
0528         if (input == KNumber::PosInfinity)
0529             last_number_ = KNumber::PosInfinity;
0530         if (input == KNumber::NegInfinity)
0531             last_number_ = KNumber::Zero;
0532         return;
0533     }
0534     last_number_ = KNumber::Euler().pow(input);
0535 }
0536 
0537 void CalcEngine::Exp10(const KNumber &input)
0538 {
0539     if (input.type() == KNumber::TYPE_ERROR) {
0540         if (input == KNumber::NaN)
0541             last_number_ = KNumber::NaN;
0542         if (input == KNumber::PosInfinity)
0543             last_number_ = KNumber::PosInfinity;
0544         if (input == KNumber::NegInfinity)
0545             last_number_ = KNumber::Zero;
0546         return;
0547     }
0548     last_number_ = KNumber(10).pow(input);
0549 }
0550 
0551 void CalcEngine::Factorial(const KNumber &input)
0552 {
0553     if (input == KNumber::PosInfinity)
0554         return;
0555     if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) {
0556         error_ = true;
0557         last_number_ = KNumber::NaN;
0558         return;
0559     }
0560 
0561     last_number_ = input.integerPart().factorial();
0562 }
0563 
0564 void CalcEngine::Gamma(const KNumber &input)
0565 {
0566     if (input == KNumber::PosInfinity)
0567         return;
0568     if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) {
0569         error_ = true;
0570         last_number_ = KNumber::NaN;
0571         return;
0572     }
0573 
0574     last_number_ = input.tgamma();
0575 }
0576 
0577 void CalcEngine::InvertSign(const KNumber &input)
0578 {
0579     last_number_ = -input;
0580 }
0581 
0582 void CalcEngine::Ln(const KNumber &input)
0583 {
0584     if (input < KNumber::Zero)
0585         last_number_ = KNumber::NaN;
0586     else if (input == KNumber::Zero)
0587         last_number_ = KNumber::NegInfinity;
0588     else if (input == KNumber::One)
0589         last_number_ = KNumber::Zero;
0590     else {
0591         last_number_ = input.ln();
0592     }
0593 }
0594 
0595 void CalcEngine::Log10(const KNumber &input)
0596 {
0597     if (input < KNumber::Zero)
0598         last_number_ = KNumber::NaN;
0599     else if (input == KNumber::Zero)
0600         last_number_ = KNumber::NegInfinity;
0601     else if (input == KNumber::One)
0602         last_number_ = KNumber::Zero;
0603     else {
0604         last_number_ = input.log10();
0605     }
0606 }
0607 
0608 void CalcEngine::ParenClose(KNumber input)
0609 {
0610     // evaluate stack until corresponding opening bracket
0611     while (!stack_.isEmpty()) {
0612         Node tmp_node = stack_.pop();
0613         if (tmp_node.operation == FUNC_BRACKET)
0614             break;
0615         input = evalOperation(tmp_node.number, tmp_node.operation, input);
0616     }
0617     last_number_ = input;
0618     return;
0619 }
0620 
0621 void CalcEngine::ParenOpen(const KNumber &input)
0622 {
0623     enterOperation(input, FUNC_BRACKET);
0624 }
0625 
0626 void CalcEngine::Reciprocal(const KNumber &input)
0627 {
0628     last_number_ = KNumber::One / input;
0629 }
0630 
0631 void CalcEngine::SinDeg(const KNumber &input)
0632 {
0633     if (input.type() == KNumber::TYPE_ERROR) {
0634         last_number_ = KNumber::NaN;
0635         return;
0636     }
0637 
0638     KNumber trunc_input = moveIntoDegInterval(input);
0639     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0640         KNumber mult = trunc_input / KNumber(90);
0641         if (mult.type() == KNumber::TYPE_INTEGER) {
0642             if (mult == KNumber::Zero)
0643                 last_number_ = KNumber::Zero;
0644             else if (mult == KNumber::One)
0645                 last_number_ = KNumber::One;
0646             else if (mult == KNumber(2))
0647                 last_number_ = KNumber::Zero;
0648             else if (mult == KNumber(3))
0649                 last_number_ = KNumber::NegOne;
0650             else
0651                 qDebug() << "Something wrong in CalcEngine::SinDeg";
0652             return;
0653         }
0654     }
0655     trunc_input = Deg2Rad(trunc_input);
0656 
0657     last_number_ = trunc_input.sin();
0658 }
0659 
0660 void CalcEngine::SinRad(const KNumber &input)
0661 {
0662     if (input.type() == KNumber::TYPE_ERROR) {
0663         last_number_ = KNumber::NaN;
0664         return;
0665     }
0666 
0667     last_number_ = input.sin();
0668 }
0669 
0670 void CalcEngine::SinGrad(const KNumber &input)
0671 {
0672     if (input.type() == KNumber::TYPE_ERROR) {
0673         last_number_ = KNumber::NaN;
0674         return;
0675     }
0676 
0677     KNumber trunc_input = moveIntoGradInterval(input);
0678     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0679         KNumber mult = trunc_input / KNumber(100);
0680         if (mult.type() == KNumber::TYPE_INTEGER) {
0681             if (mult == KNumber::Zero)
0682                 last_number_ = KNumber::Zero;
0683             else if (mult == KNumber::One)
0684                 last_number_ = KNumber::One;
0685             else if (mult == KNumber(2))
0686                 last_number_ = KNumber::Zero;
0687             else if (mult == KNumber(3))
0688                 last_number_ = KNumber::NegOne;
0689             else
0690                 qDebug() << "Something wrong in CalcEngine::SinGrad";
0691             return;
0692         }
0693     }
0694 
0695     trunc_input = Gra2Rad(trunc_input);
0696 
0697     last_number_ = trunc_input.sin();
0698 }
0699 
0700 void CalcEngine::SinHyp(const KNumber &input)
0701 {
0702     if (input.type() == KNumber::TYPE_ERROR) {
0703         if (input == KNumber::NaN)
0704             last_number_ = KNumber::NaN;
0705         if (input == KNumber::PosInfinity)
0706             last_number_ = KNumber::PosInfinity;
0707         if (input == KNumber::NegInfinity)
0708             last_number_ = KNumber::NegInfinity;
0709         return;
0710     }
0711 
0712     last_number_ = input.sinh();
0713 }
0714 
0715 void CalcEngine::Square(const KNumber &input)
0716 {
0717     last_number_ = input * input;
0718 }
0719 
0720 void CalcEngine::SquareRoot(const KNumber &input)
0721 {
0722     last_number_ = input.sqrt();
0723 }
0724 
0725 void CalcEngine::StatClearAll(const KNumber &input)
0726 {
0727     Q_UNUSED(input);
0728     stats.clearAll();
0729 }
0730 
0731 void CalcEngine::StatCount(const KNumber &input)
0732 {
0733     Q_UNUSED(input);
0734     last_number_ = KNumber(stats.count());
0735 }
0736 
0737 void CalcEngine::StatDataNew(const KNumber &input)
0738 {
0739     stats.enterData(input);
0740     last_number_ = KNumber(stats.count());
0741 }
0742 
0743 void CalcEngine::StatDataDel(const KNumber &input)
0744 {
0745     Q_UNUSED(input);
0746     stats.clearLast();
0747     last_number_ = KNumber(stats.count());
0748 }
0749 
0750 void CalcEngine::StatMean(const KNumber &input)
0751 {
0752     Q_UNUSED(input);
0753     last_number_ = stats.mean();
0754 
0755     error_ = stats.error();
0756 }
0757 
0758 void CalcEngine::StatMedian(const KNumber &input)
0759 {
0760     Q_UNUSED(input);
0761     last_number_ = stats.median();
0762 
0763     error_ = stats.error();
0764 }
0765 
0766 void CalcEngine::StatStdDeviation(const KNumber &input)
0767 {
0768     Q_UNUSED(input);
0769     last_number_ = stats.std();
0770 
0771     error_ = stats.error();
0772 }
0773 
0774 void CalcEngine::StatStdSample(const KNumber &input)
0775 {
0776     Q_UNUSED(input);
0777     last_number_ = stats.sample_std();
0778 
0779     error_ = stats.error();
0780 }
0781 
0782 void CalcEngine::StatSum(const KNumber &input)
0783 {
0784     Q_UNUSED(input);
0785     last_number_ = stats.sum();
0786 }
0787 
0788 void CalcEngine::StatSumSquares(const KNumber &input)
0789 {
0790     Q_UNUSED(input);
0791     last_number_ = stats.sum_of_squares();
0792 
0793     error_ = stats.error();
0794 }
0795 
0796 void CalcEngine::TangensDeg(const KNumber &input)
0797 {
0798     if (input.type() == KNumber::TYPE_ERROR) {
0799         last_number_ = KNumber::NaN;
0800         return;
0801     }
0802 
0803     SinDeg(input);
0804     KNumber arg1 = last_number_;
0805     CosDeg(input);
0806     KNumber arg2 = last_number_;
0807 
0808     last_number_ = arg1 / arg2;
0809 }
0810 
0811 void CalcEngine::TangensRad(const KNumber &input)
0812 {
0813     if (input.type() == KNumber::TYPE_ERROR) {
0814         last_number_ = KNumber::NaN;
0815         return;
0816     }
0817 
0818     SinRad(input);
0819     KNumber arg1 = last_number_;
0820     CosRad(input);
0821     KNumber arg2 = last_number_;
0822 
0823     last_number_ = arg1 / arg2;
0824 }
0825 
0826 void CalcEngine::TangensGrad(const KNumber &input)
0827 {
0828     if (input.type() == KNumber::TYPE_ERROR) {
0829         last_number_ = KNumber::NaN;
0830         return;
0831     }
0832 
0833     SinGrad(input);
0834     KNumber arg1 = last_number_;
0835     CosGrad(input);
0836     KNumber arg2 = last_number_;
0837 
0838     last_number_ = arg1 / arg2;
0839 }
0840 
0841 void CalcEngine::TangensHyp(const KNumber &input)
0842 {
0843     if (input.type() == KNumber::TYPE_ERROR) {
0844         if (input == KNumber::NaN)
0845             last_number_ = KNumber::NaN;
0846         if (input == KNumber::PosInfinity)
0847             last_number_ = KNumber::One;
0848         if (input == KNumber::NegInfinity)
0849             last_number_ = KNumber::NegOne;
0850         return;
0851     }
0852 
0853     last_number_ = input.tanh();
0854 }
0855 
0856 KNumber CalcEngine::evalOperation(const KNumber &arg1, Operation operation, const KNumber &arg2)
0857 {
0858     if (!percent_mode_ || Operator[operation].prcnt_ptr == nullptr) {
0859         return (Operator[operation].arith_ptr)(arg1, arg2);
0860     } else {
0861         percent_mode_ = false;
0862         return (Operator[operation].prcnt_ptr)(arg1, arg2);
0863     }
0864 }
0865 
0866 void CalcEngine::enterOperation(const KNumber &number, Operation func, Repeat allow_repeat)
0867 {
0868     Node tmp_node;
0869 
0870     if (func == FUNC_BRACKET) {
0871         tmp_node.number = KNumber::Zero;
0872         tmp_node.operation = FUNC_BRACKET;
0873 
0874         stack_.push(tmp_node);
0875 
0876         return;
0877     }
0878 
0879     if (func == FUNC_PERCENT) {
0880         percent_mode_ = true;
0881     }
0882 
0883     tmp_node.number = number;
0884     tmp_node.operation = func;
0885 
0886     if (KCalcSettings::repeatLastOperation()) {
0887         if (func != FUNC_EQUAL && func != FUNC_PERCENT) {
0888             last_operation_ = tmp_node.operation;
0889             repeat_mode_ = false;
0890         }
0891 
0892         if (func == FUNC_EQUAL || func == FUNC_PERCENT) {
0893             if (!repeat_mode_) {
0894                 repeat_mode_ = last_operation_ != FUNC_EQUAL;
0895                 last_repeat_number_ = number;
0896             } else if (allow_repeat == REPEAT_ALLOW) {
0897                 Node repeat_node;
0898                 repeat_node.operation = last_operation_;
0899                 repeat_node.number = number;
0900                 tmp_node.number = last_repeat_number_;
0901                 stack_.push(repeat_node);
0902             }
0903         }
0904     }
0905 
0906     if (getOnlyUpdateOperation() && !stack_.isEmpty() && !(func == FUNC_EQUAL || func == FUNC_PERCENT))
0907         stack_.top().operation = func;
0908     else
0909         stack_.push(tmp_node);
0910 
0911     // The check for '=' or '%' is unnecessary; it is just a safety measure
0912     if (!((func == FUNC_EQUAL) || (func == FUNC_PERCENT)))
0913         setOnlyUpdateOperation(true);
0914 
0915     evalStack();
0916 }
0917 
0918 bool CalcEngine::evalStack()
0919 {
0920     // this should never happen
0921     Q_ASSERT(!stack_.isEmpty());
0922 
0923     Node tmp_node = stack_.pop();
0924 
0925     while (!stack_.isEmpty()) {
0926         Node tmp_node2 = stack_.pop();
0927         if (Operator[tmp_node.operation].precedence <= Operator[tmp_node2.operation].precedence) {
0928             if (tmp_node2.operation == FUNC_BRACKET)
0929                 continue;
0930             const KNumber tmp_result = evalOperation(tmp_node2.number, tmp_node2.operation, tmp_node.number);
0931             tmp_node.number = tmp_result;
0932         } else {
0933             stack_.push(tmp_node2);
0934             break;
0935         }
0936     }
0937 
0938     if (tmp_node.operation != FUNC_EQUAL && tmp_node.operation != FUNC_PERCENT)
0939         stack_.push(tmp_node);
0940 
0941     last_number_ = tmp_node.number;
0942     return true;
0943 }
0944 
0945 void CalcEngine::Reset()
0946 {
0947     percent_mode_ = false;
0948     repeat_mode_ = false;
0949     last_operation_ = FUNC_EQUAL;
0950     error_ = false;
0951     last_number_ = KNumber::Zero;
0952     only_update_operation_ = false;
0953 
0954     stack_.clear();
0955 }
0956 
0957 void CalcEngine::setOnlyUpdateOperation(bool update)
0958 {
0959     only_update_operation_ = update;
0960 }
0961 
0962 bool CalcEngine::getOnlyUpdateOperation() const
0963 {
0964     return only_update_operation_;
0965 }