File indexing completed on 2024-04-28 09:45:26

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