File indexing completed on 2024-04-28 05:49:44

0001 /*
0002     SPDX-FileCopyrightText: 2023 Gabriel Barrantes <gabriel.barrantes.dev@outlook.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "kcalc_core_p.h"
0007 #include "knumber.h"
0008 #include "stats.h"
0009 
0010 KNumber CalcEngine_p::Deg2Rad(const KNumber &x)
0011 {
0012     return x * (KNumber::Pi() / KNumber(180));
0013 }
0014 
0015 KNumber CalcEngine_p::Gra2Rad(const KNumber &x)
0016 {
0017     return x * (KNumber::Pi() / KNumber(200));
0018 }
0019 
0020 KNumber CalcEngine_p::Rad2Deg(const KNumber &x)
0021 {
0022     return x * (KNumber(180) / KNumber::Pi());
0023 }
0024 
0025 KNumber CalcEngine_p::Rad2Gra(const KNumber &x)
0026 {
0027     return x * (KNumber(200) / KNumber::Pi());
0028 }
0029 
0030 KNumber CalcEngine_p::ExecOr(const KNumber &left_op, const KNumber &right_op)
0031 {
0032     return left_op | right_op;
0033 }
0034 
0035 KNumber CalcEngine_p::ExecXor(const KNumber &left_op, const KNumber &right_op)
0036 {
0037     return left_op ^ right_op;
0038 }
0039 
0040 KNumber CalcEngine_p::ExecAnd(const KNumber &left_op, const KNumber &right_op)
0041 {
0042     return left_op & right_op;
0043 }
0044 
0045 KNumber CalcEngine_p::ExecLsh(const KNumber &left_op, const KNumber &right_op)
0046 {
0047     return left_op << right_op;
0048 }
0049 
0050 KNumber CalcEngine_p::ExecRsh(const KNumber &left_op, const KNumber &right_op)
0051 {
0052     return left_op >> right_op;
0053 }
0054 
0055 KNumber CalcEngine_p::ExecAdd(const KNumber &left_op, const KNumber &right_op)
0056 {
0057     return left_op + right_op;
0058 }
0059 
0060 KNumber CalcEngine_p::ExecSubtract(const KNumber &left_op, const KNumber &right_op)
0061 {
0062     return left_op - right_op;
0063 }
0064 
0065 KNumber CalcEngine_p::ExecMultiply(const KNumber &left_op, const KNumber &right_op)
0066 {
0067     return left_op * right_op;
0068 }
0069 
0070 KNumber CalcEngine_p::ExecDivide(const KNumber &left_op, const KNumber &right_op)
0071 {
0072     return left_op / right_op;
0073 }
0074 
0075 KNumber CalcEngine_p::ExecMod(const KNumber &left_op, const KNumber &right_op)
0076 {
0077     return left_op % right_op;
0078 }
0079 
0080 KNumber CalcEngine_p::ExecIntDiv(const KNumber &left_op, const KNumber &right_op)
0081 {
0082     return (left_op / right_op).integerPart();
0083 }
0084 
0085 KNumber CalcEngine_p::ExecBinom(const KNumber &left_op, const KNumber &right_op)
0086 {
0087     return left_op.bin(right_op);
0088 }
0089 
0090 KNumber CalcEngine_p::ExecPower(const KNumber &left_op, const KNumber &right_op)
0091 {
0092     return left_op.pow(right_op);
0093 }
0094 
0095 KNumber CalcEngine_p::ExecPwrRoot(const KNumber &left_op, const KNumber &right_op)
0096 {
0097     return left_op.pow(KNumber::One / right_op);
0098 }
0099 
0100 KNumber CalcEngine_p::ExecAddP(const KNumber &left_op, const KNumber &right_op)
0101 {
0102     return left_op * (KNumber::One + right_op / KNumber(100));
0103 }
0104 
0105 KNumber CalcEngine_p::ExecSubP(const KNumber &left_op, const KNumber &right_op)
0106 {
0107     return left_op * (KNumber::One - right_op / KNumber(100));
0108 }
0109 
0110 KNumber CalcEngine_p::ExecMultiplyP(const KNumber &left_op, const KNumber &right_op)
0111 {
0112     return left_op * right_op / KNumber(100);
0113 }
0114 
0115 KNumber CalcEngine_p::ExecDivideP(const KNumber &left_op, const KNumber &right_op)
0116 {
0117     return left_op * KNumber(100) / right_op;
0118 }
0119 
0120 // move a number into the interval [0,360) by adding multiples of 360
0121 KNumber CalcEngine_p::moveIntoDegInterval(const KNumber &num)
0122 {
0123     KNumber tmp_num = num - (num / KNumber(360)).integerPart() * KNumber(360);
0124     if (tmp_num < KNumber::Zero)
0125         return tmp_num + KNumber(360);
0126     return tmp_num;
0127 }
0128 
0129 // move a number into the interval [0,400) by adding multiples of 400
0130 KNumber CalcEngine_p::moveIntoGradInterval(const KNumber &num)
0131 {
0132     KNumber tmp_num = num - (num / KNumber(400)).integerPart() * KNumber(400);
0133     if (tmp_num < KNumber::Zero)
0134         return tmp_num + KNumber(400);
0135     return tmp_num;
0136 }
0137 
0138 KNumber CalcEngine_p::ArcCosDeg(const KNumber &input)
0139 {
0140     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0141         return KNumber::NaN;
0142     }
0143 
0144     if (input.type() == KNumber::TYPE_INTEGER) {
0145         if (input == KNumber::One) {
0146             return KNumber::Zero;
0147         }
0148         if (input == -KNumber::One) {
0149             return KNumber(180);
0150         }
0151         if (input == KNumber::Zero) {
0152             return KNumber(90);
0153         }
0154     }
0155     return Rad2Deg(input.acos());
0156 }
0157 
0158 KNumber CalcEngine_p::ArcCosRad(const KNumber &input)
0159 {
0160     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0161         return KNumber::NaN;
0162     }
0163     return input.acos();
0164 }
0165 
0166 KNumber CalcEngine_p::ArcCosGrad(const KNumber &input)
0167 {
0168     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0169         return KNumber::NaN;
0170     }
0171     if (input.type() == KNumber::TYPE_INTEGER) {
0172         if (input == KNumber::One) {
0173             return KNumber::Zero;
0174         }
0175         if (input == -KNumber::One) {
0176             return KNumber(200);
0177         }
0178         if (input == KNumber::Zero) {
0179             return KNumber(100);
0180         }
0181     }
0182     return Rad2Gra(input.acos());
0183 }
0184 
0185 KNumber CalcEngine_p::ArcSinDeg(const KNumber &input)
0186 {
0187     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0188         return KNumber::NaN;
0189     }
0190     if (input.type() == KNumber::TYPE_INTEGER) {
0191         if (input == KNumber::One) {
0192             return KNumber(90);
0193         }
0194         if (input == -KNumber::One) {
0195             return KNumber(-90);
0196         }
0197         if (input == KNumber::Zero) {
0198             return KNumber::Zero;
0199         }
0200     }
0201     return Rad2Deg(input.asin());
0202 }
0203 
0204 KNumber CalcEngine_p::ArcSinRad(const KNumber &input)
0205 {
0206     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0207         return KNumber::NaN;
0208     }
0209     return input.asin();
0210 }
0211 
0212 KNumber CalcEngine_p::ArcSinGrad(const KNumber &input)
0213 {
0214     if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) {
0215         return KNumber::NaN;
0216     }
0217     if (input.type() == KNumber::TYPE_INTEGER) {
0218         if (input == KNumber::One) {
0219             return KNumber(100);
0220         }
0221         if (input == -KNumber::One) {
0222             return KNumber(-100);
0223         }
0224         if (input == KNumber::Zero) {
0225             return KNumber::Zero;
0226         }
0227     }
0228     return Rad2Gra(input.asin());
0229 }
0230 
0231 KNumber CalcEngine_p::ArcTangensDeg(const KNumber &input)
0232 {
0233     if (input.type() == KNumber::TYPE_ERROR) {
0234         if (input == KNumber::NaN)
0235             return KNumber::NaN;
0236         if (input == KNumber::PosInfinity)
0237             return KNumber(90);
0238         if (input == KNumber::NegInfinity)
0239             return KNumber(-90);
0240     }
0241 
0242     return Rad2Deg(input.atan());
0243 }
0244 
0245 KNumber CalcEngine_p::ArcTangensRad(const KNumber &input)
0246 {
0247     if (input.type() == KNumber::TYPE_ERROR) {
0248         if (input == KNumber::NaN)
0249             return KNumber::NaN;
0250         if (input == KNumber::PosInfinity)
0251             return KNumber::Pi() / KNumber(2);
0252         if (input == KNumber::NegInfinity)
0253             return -KNumber::Pi() / KNumber(2);
0254     }
0255 
0256     return input.atan();
0257 }
0258 
0259 KNumber CalcEngine_p::ArcTangensGrad(const KNumber &input)
0260 {
0261     if (input.type() == KNumber::TYPE_ERROR) {
0262         if (input == KNumber::NaN)
0263             return KNumber::NaN;
0264         if (input == KNumber::PosInfinity)
0265             return KNumber(100);
0266         if (input == KNumber::NegInfinity)
0267             return KNumber(-100);
0268     }
0269 
0270     return Rad2Gra(input.atan());
0271 }
0272 
0273 KNumber CalcEngine_p::AreaCosHyp(const KNumber &input)
0274 {
0275     if (input.type() == KNumber::TYPE_ERROR) {
0276         if (input == KNumber::NaN)
0277             return KNumber::NaN;
0278         if (input == KNumber::PosInfinity)
0279             return KNumber::PosInfinity;
0280         if (input == KNumber::NegInfinity)
0281             return KNumber::NaN;
0282     }
0283 
0284     if (input < KNumber::One) {
0285         return KNumber::NaN;
0286     }
0287     if (input == KNumber::One) {
0288         return KNumber::Zero;
0289     }
0290     return input.acosh();
0291 }
0292 
0293 KNumber CalcEngine_p::AreaSinHyp(const KNumber &input)
0294 {
0295     if (input.type() == KNumber::TYPE_ERROR) {
0296         if (input == KNumber::NaN)
0297             return KNumber::NaN;
0298         if (input == KNumber::PosInfinity)
0299             return KNumber::PosInfinity;
0300         if (input == KNumber::NegInfinity)
0301             return KNumber::NegInfinity;
0302     }
0303 
0304     if (input == KNumber::Zero) {
0305         return KNumber::Zero;
0306     }
0307     return input.asinh();
0308 }
0309 
0310 KNumber CalcEngine_p::AreaTangensHyp(const KNumber &input)
0311 {
0312     if (input.type() == KNumber::TYPE_ERROR) {
0313         return KNumber::NaN;
0314     }
0315 
0316     if (input < -KNumber::One || input > KNumber::One) {
0317         return KNumber::NaN;
0318     }
0319     if (input == KNumber::One) {
0320         return KNumber::PosInfinity;
0321     }
0322     if (input == -KNumber::One) {
0323         return KNumber::NegInfinity;
0324     }
0325     return input.atanh();
0326 }
0327 
0328 KNumber CalcEngine_p::Complement(const KNumber &input)
0329 {
0330     if (input.type() != KNumber::TYPE_INTEGER) {
0331         return KNumber::NaN;
0332     }
0333 
0334     return ~input;
0335 }
0336 
0337 KNumber CalcEngine_p::CosDeg(const KNumber &input)
0338 {
0339     if (input.type() == KNumber::TYPE_ERROR) {
0340         return KNumber::NaN;
0341     }
0342 
0343     KNumber trunc_input = moveIntoDegInterval(input);
0344 
0345     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0346         KNumber mult = trunc_input / KNumber(90);
0347         if (mult.type() == KNumber::TYPE_INTEGER) {
0348             if (mult == KNumber::Zero)
0349                 return KNumber::One;
0350             else if (mult == KNumber::One)
0351                 return KNumber::Zero;
0352             else if (mult == KNumber(2))
0353                 return KNumber::NegOne;
0354             else if (mult == KNumber(3))
0355                 return KNumber::Zero;
0356             else
0357                 return KNumber::NaN;
0358         }
0359     }
0360 
0361     trunc_input = Deg2Rad(trunc_input);
0362     return trunc_input.cos();
0363 }
0364 
0365 KNumber CalcEngine_p::CosRad(const KNumber &input)
0366 {
0367     if (input.type() == KNumber::TYPE_ERROR) {
0368         return KNumber::NaN;
0369     }
0370 
0371     return input.cos();
0372 }
0373 
0374 KNumber CalcEngine_p::CosGrad(const KNumber &input)
0375 {
0376     if (input.type() == KNumber::TYPE_ERROR) {
0377         return KNumber::NaN;
0378     }
0379     KNumber trunc_input = moveIntoGradInterval(input);
0380     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0381         KNumber mult = trunc_input / KNumber(100);
0382         if (mult.type() == KNumber::TYPE_INTEGER) {
0383             if (mult == KNumber::Zero)
0384                 return KNumber::One;
0385             else if (mult == KNumber::One)
0386                 return KNumber::Zero;
0387             else if (mult == KNumber(2))
0388                 return KNumber::NegOne;
0389             else if (mult == KNumber(3))
0390                 return KNumber::Zero;
0391             else
0392                 return KNumber::NaN;
0393         }
0394     }
0395     trunc_input = Gra2Rad(trunc_input);
0396 
0397     return trunc_input.cos();
0398 }
0399 
0400 KNumber CalcEngine_p::CosHyp(const KNumber &input)
0401 {
0402     if (input.type() == KNumber::TYPE_ERROR) {
0403         if (input == KNumber::NaN)
0404             return KNumber::NaN;
0405         if (input == KNumber::PosInfinity)
0406             return KNumber::PosInfinity;
0407         if (input == KNumber::NegInfinity)
0408             return KNumber::PosInfinity;
0409         return KNumber::NaN;
0410     }
0411 
0412     return input.cosh();
0413 }
0414 
0415 KNumber CalcEngine_p::Cube(const KNumber &input)
0416 {
0417     return input * input * input;
0418 }
0419 
0420 KNumber CalcEngine_p::CubeRoot(const KNumber &input)
0421 {
0422     return input.cbrt();
0423 }
0424 
0425 KNumber CalcEngine_p::Exp(const KNumber &input)
0426 {
0427     if (input.type() == KNumber::TYPE_ERROR) {
0428         if (input == KNumber::NaN)
0429             return KNumber::NaN;
0430         if (input == KNumber::PosInfinity)
0431             return KNumber::PosInfinity;
0432         if (input == KNumber::NegInfinity)
0433             return KNumber::Zero;
0434         return KNumber::NaN;
0435     }
0436     return KNumber::Euler().pow(input);
0437 }
0438 
0439 KNumber CalcEngine_p::Exp10(const KNumber &input)
0440 {
0441     if (input.type() == KNumber::TYPE_ERROR) {
0442         if (input == KNumber::NaN)
0443             return KNumber::NaN;
0444         if (input == KNumber::PosInfinity)
0445             return KNumber::PosInfinity;
0446         if (input == KNumber::NegInfinity)
0447             return KNumber::Zero;
0448         return KNumber::NaN;
0449     }
0450     return KNumber(10).pow(input);
0451 }
0452 
0453 KNumber CalcEngine_p::Factorial(const KNumber &input)
0454 {
0455     if (input == KNumber::PosInfinity)
0456         return KNumber::PosInfinity;
0457     if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) {
0458         return KNumber::NaN;
0459     }
0460 
0461     return input.integerPart().factorial();
0462 }
0463 
0464 KNumber CalcEngine_p::Gamma(const KNumber &input)
0465 {
0466     if (input == KNumber::PosInfinity)
0467         return KNumber::PosInfinity;
0468     if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) {
0469         return KNumber::NaN;
0470     }
0471 
0472     return input.tgamma();
0473 }
0474 
0475 KNumber CalcEngine_p::InvertSign(const KNumber &input)
0476 {
0477     return -input;
0478 }
0479 
0480 KNumber CalcEngine_p::Ln(const KNumber &input)
0481 {
0482     if (input < KNumber::Zero)
0483         return KNumber::NaN;
0484     else if (input == KNumber::Zero)
0485         return KNumber::NegInfinity;
0486     else if (input == KNumber::One)
0487         return KNumber::Zero;
0488     else {
0489         return input.ln();
0490     }
0491 }
0492 
0493 KNumber CalcEngine_p::Log10(const KNumber &input)
0494 {
0495     if (input < KNumber::Zero)
0496         return KNumber::NaN;
0497     else if (input == KNumber::Zero)
0498         return KNumber::NegInfinity;
0499     else if (input == KNumber::One)
0500         return KNumber::Zero;
0501     else {
0502         return input.log10();
0503     }
0504 }
0505 
0506 KNumber CalcEngine_p::Reciprocal(const KNumber &input)
0507 {
0508     return KNumber::One / input;
0509 }
0510 
0511 KNumber CalcEngine_p::SinDeg(const KNumber &input)
0512 {
0513     if (input.type() == KNumber::TYPE_ERROR) {
0514         return KNumber::NaN;
0515     }
0516 
0517     KNumber trunc_input = moveIntoDegInterval(input);
0518     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0519         KNumber mult = trunc_input / KNumber(90);
0520         if (mult.type() == KNumber::TYPE_INTEGER) {
0521             if (mult == KNumber::Zero)
0522                 return KNumber::Zero;
0523             else if (mult == KNumber::One)
0524                 return KNumber::One;
0525             else if (mult == KNumber(2))
0526                 return KNumber::Zero;
0527             else if (mult == KNumber(3))
0528                 return KNumber::NegOne;
0529             else
0530                 return KNumber::NaN;
0531         }
0532     }
0533     trunc_input = Deg2Rad(trunc_input);
0534 
0535     return trunc_input.sin();
0536 }
0537 
0538 KNumber CalcEngine_p::SinRad(const KNumber &input)
0539 {
0540     if (input.type() == KNumber::TYPE_ERROR) {
0541         return KNumber::NaN;
0542     }
0543 
0544     return input.sin();
0545 }
0546 
0547 KNumber CalcEngine_p::SinGrad(const KNumber &input)
0548 {
0549     if (input.type() == KNumber::TYPE_ERROR) {
0550         return KNumber::NaN;
0551     }
0552 
0553     KNumber trunc_input = moveIntoGradInterval(input);
0554     if (trunc_input.type() == KNumber::TYPE_INTEGER) {
0555         KNumber mult = trunc_input / KNumber(100);
0556         if (mult.type() == KNumber::TYPE_INTEGER) {
0557             if (mult == KNumber::Zero)
0558                 return KNumber::Zero;
0559             else if (mult == KNumber::One)
0560                 return KNumber::One;
0561             else if (mult == KNumber(2))
0562                 return KNumber::Zero;
0563             else if (mult == KNumber(3))
0564                 return KNumber::NegOne;
0565             else
0566                 return KNumber::NaN;
0567         }
0568     }
0569 
0570     trunc_input = Gra2Rad(trunc_input);
0571 
0572     return trunc_input.sin();
0573 }
0574 
0575 KNumber CalcEngine_p::SinHyp(const KNumber &input)
0576 {
0577     if (input.type() == KNumber::TYPE_ERROR) {
0578         if (input == KNumber::NaN)
0579             return KNumber::NaN;
0580         if (input == KNumber::PosInfinity)
0581             return KNumber::PosInfinity;
0582         if (input == KNumber::NegInfinity)
0583             return KNumber::NegInfinity;
0584         return KNumber::NaN;
0585     }
0586 
0587     return input.sinh();
0588 }
0589 
0590 KNumber CalcEngine_p::Square(const KNumber &input)
0591 {
0592     return input * input;
0593 }
0594 
0595 KNumber CalcEngine_p::SquareRoot(const KNumber &input)
0596 {
0597     return input.sqrt();
0598 }
0599 
0600 KNumber CalcEngine_p::Percentage(const KNumber &input)
0601 {
0602     return ExecDivide(input, KNumber::OneHundred);
0603 }
0604 
0605 void CalcEngine_p::StatClearAll(const KNumber &input)
0606 {
0607     Q_UNUSED(input);
0608     stats.clearAll();
0609 }
0610 
0611 KNumber CalcEngine_p::StatCount(const KNumber &input)
0612 {
0613     Q_UNUSED(input);
0614     return KNumber(stats.count());
0615 }
0616 
0617 void CalcEngine_p::StatDataNew(const KNumber &input)
0618 {
0619     stats.enterData(input);
0620 }
0621 
0622 void CalcEngine_p::StatDataDel(const KNumber &input)
0623 {
0624     Q_UNUSED(input);
0625     stats.clearLast();
0626 }
0627 
0628 KNumber CalcEngine_p::StatMean(const KNumber &input)
0629 {
0630     Q_UNUSED(input);
0631     return stats.mean();
0632 }
0633 
0634 KNumber CalcEngine_p::StatMedian(const KNumber &input)
0635 {
0636     Q_UNUSED(input);
0637     return stats.median();
0638 }
0639 
0640 KNumber CalcEngine_p::StatStdDeviation(const KNumber &input)
0641 {
0642     Q_UNUSED(input);
0643     return stats.std();
0644 }
0645 
0646 KNumber CalcEngine_p::StatStdSample(const KNumber &input)
0647 {
0648     Q_UNUSED(input);
0649     return stats.sample_std();
0650 }
0651 
0652 KNumber CalcEngine_p::StatSum(const KNumber &input)
0653 {
0654     Q_UNUSED(input);
0655     return stats.sum();
0656 }
0657 
0658 KNumber CalcEngine_p::StatSumSquares(const KNumber &input)
0659 {
0660     Q_UNUSED(input);
0661     return stats.sum_of_squares();
0662 }
0663 
0664 KNumber CalcEngine_p::TangensDeg(const KNumber &input)
0665 {
0666     if (input.type() == KNumber::TYPE_ERROR) {
0667         return KNumber::NaN;
0668     }
0669 
0670     KNumber arg1 = SinDeg(input);
0671     KNumber arg2 = CosDeg(input);
0672 
0673     return arg1 / arg2;
0674 }
0675 
0676 KNumber CalcEngine_p::TangensRad(const KNumber &input)
0677 {
0678     if (input.type() == KNumber::TYPE_ERROR) {
0679         return KNumber::NaN;
0680     }
0681 
0682     KNumber arg1 = SinRad(input);
0683     KNumber arg2 = CosRad(input);
0684 
0685     return arg1 / arg2;
0686 }
0687 
0688 KNumber CalcEngine_p::TangensGrad(const KNumber &input)
0689 {
0690     if (input.type() == KNumber::TYPE_ERROR) {
0691         return KNumber::NaN;
0692     }
0693 
0694     KNumber arg1 = SinGrad(input);
0695     KNumber arg2 = CosGrad(input);
0696 
0697     return arg1 / arg2;
0698 }
0699 
0700 KNumber CalcEngine_p::TangensHyp(const KNumber &input)
0701 {
0702     if (input.type() == KNumber::TYPE_ERROR) {
0703         if (input == KNumber::NaN)
0704             return KNumber::NaN;
0705         if (input == KNumber::PosInfinity)
0706             return KNumber::One;
0707         if (input == KNumber::NegInfinity)
0708             return KNumber::NegOne;
0709         return KNumber::NaN;
0710     }
0711 
0712     return input.tanh();
0713 }