File indexing completed on 2024-04-21 05:50:06

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_token.h"
0012 #include "knumber.h"
0013 #include "stats.h"
0014 #include <QQueue>
0015 
0016 #include <QDebug>
0017 
0018 CalcEngine::CalcEngine()
0019     : buffer_result_(KNumber::Zero)
0020 {
0021     error_ = false;
0022 }
0023 
0024 KNumber CalcEngine::lastOutput(bool &error) const
0025 {
0026     error = error_;
0027     return buffer_result_;
0028 }
0029 
0030 void CalcEngine::StatClearAll()
0031 {
0032     stats.clearAll();
0033 }
0034 
0035 void CalcEngine::StatCount(const KNumber &input)
0036 {
0037     Q_UNUSED(input);
0038     buffer_result_ = KNumber(stats.count());
0039 }
0040 
0041 void CalcEngine::StatDataNew(const KNumber &input)
0042 {
0043     stats.enterData(input);
0044     buffer_result_ = KNumber(stats.count());
0045 }
0046 
0047 void CalcEngine::StatDataDel()
0048 {
0049     stats.clearLast();
0050     buffer_result_ = KNumber(stats.count());
0051 }
0052 
0053 void CalcEngine::StatMean(const KNumber &input)
0054 {
0055     Q_UNUSED(input);
0056     buffer_result_ = stats.mean();
0057 
0058     error_ = stats.error();
0059 }
0060 
0061 void CalcEngine::StatMedian(const KNumber &input)
0062 {
0063     Q_UNUSED(input);
0064     buffer_result_ = stats.median();
0065 
0066     error_ = stats.error();
0067 }
0068 
0069 void CalcEngine::StatStdDeviation(const KNumber &input)
0070 {
0071     Q_UNUSED(input);
0072     buffer_result_ = stats.std();
0073 
0074     error_ = stats.error();
0075 }
0076 
0077 void CalcEngine::StatStdSample(const KNumber &input)
0078 {
0079     Q_UNUSED(input);
0080     buffer_result_ = stats.sample_std();
0081 
0082     error_ = stats.error();
0083 }
0084 
0085 void CalcEngine::StatSum(const KNumber &input)
0086 {
0087     Q_UNUSED(input);
0088     buffer_result_ = stats.sum();
0089 }
0090 
0091 void CalcEngine::StatSumSquares(const KNumber &input)
0092 {
0093     Q_UNUSED(input);
0094     buffer_result_ = stats.sum_of_squares();
0095 
0096     error_ = stats.error();
0097 }
0098 
0099 void CalcEngine::Reset()
0100 {
0101     error_ = false;
0102     buffer_result_ = KNumber::Zero;
0103     StatClearAll();
0104 }
0105 
0106 int CalcEngine::calculate(const QQueue<KCalcToken> tokenBuffer, int &errorIndex)
0107 {
0108     token_stack_.clear();
0109     int token_index = 0;
0110     int buffer_size = tokenBuffer.size();
0111     qDebug() << "Token buffer size: " << buffer_size;
0112 
0113     KCalcToken const *tokenFunction;
0114     KCalcToken const *tokenFirstArg;
0115     KNumber result;
0116     KCalcToken::TokenType tokenType;
0117 
0118     while (token_index < buffer_size) {
0119         qDebug() << "Processing token queue at: " << token_index;
0120         KCalcToken::TokenCode tokenCode = tokenBuffer.at(token_index).getTokenCode();
0121 
0122         if (tokenCode == KCalcToken::TokenCode::EQUAL) {
0123             token_index++;
0124             continue;
0125         }
0126 
0127         tokenType = tokenBuffer.at(token_index).getTokenType();
0128         switch (tokenType) {
0129         case KCalcToken::TokenType::KNUMBER_TYPE:
0130             if (tokenCode == KCalcToken::TokenCode::ANS) {
0131                 insert_KNumber_Token_In_Stack_(KCalcToken(buffer_result_));
0132             } else {
0133                 insert_KNumber_Token_In_Stack_(tokenBuffer.at(token_index));
0134             }
0135             token_index++;
0136             break;
0137         case KCalcToken::TokenType::RIGHT_UNARY_FUNCTION_TYPE:
0138             if (token_index + 1 >= buffer_size) {
0139                 errorIndex = token_index;
0140                 return -1;
0141             }
0142             if (!token_stack_.isEmpty()) {
0143                 if (token_stack_.last().isKNumber()) {
0144                     insert_Binary_Function_Token_In_Stack_(multiplication_Token_);
0145                 }
0146             }
0147 
0148             token_stack_.push_back(tokenBuffer.at(token_index));
0149             token_index++;
0150             break;
0151         case KCalcToken::TokenType::LEFT_UNARY_FUNCTION_TYPE:
0152             if (token_stack_.isEmpty()) {
0153                 errorIndex = token_index;
0154                 return -1;
0155             }
0156             if (!token_stack_.last().isKNumber()) {
0157                 errorIndex = token_index;
0158                 return -1;
0159             }
0160 
0161             if (token_stack_.size() > 1) {
0162                 while (token_stack_.at(token_stack_.size() - 2).isRightUnaryFunction()) {
0163                     tokenFunction = &token_stack_.at(token_stack_.size() - 2);
0164                     tokenFirstArg = &token_stack_.last();
0165                     KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0166                     token_stack_.pop_back();
0167                     token_stack_.pop_back();
0168                     insert_KNumber_Token_In_Stack_(KCalcToken(result));
0169                     if (token_stack_.size() == 1) {
0170                         break;
0171                     }
0172                 }
0173             }
0174 
0175             tokenFunction = &tokenBuffer.at(token_index);
0176             tokenFirstArg = &token_stack_.last();
0177             result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0178             token_stack_.pop_back();
0179             insert_KNumber_Token_In_Stack_(KCalcToken(result));
0180             token_index++;
0181             break;
0182         case KCalcToken::TokenType::BINARY_FUNCTION_TYPE:
0183             if (token_index + 1 >= buffer_size) {
0184                 errorIndex = token_index;
0185                 return -1;
0186             }
0187 
0188             if (token_stack_.isEmpty()) {
0189                 switch (tokenCode) {
0190                 case KCalcToken::TokenCode::PLUS:
0191                 case KCalcToken::TokenCode::MINUS:
0192                     token_stack_.push_back(KCalcToken(KNumber::Zero));
0193                     break;
0194                 default:
0195                     errorIndex = token_index;
0196                     return -1;
0197                     break;
0198                 }
0199             }
0200 
0201             switch (token_stack_.last().getTokenType()) {
0202             case KCalcToken::TokenType::BINARY_FUNCTION_TYPE:
0203                 if (tokenCode == KCalcToken::TokenCode::PLUS) {
0204                     token_index++;
0205                     continue;
0206                 } else if (tokenCode == KCalcToken::TokenCode::MINUS) {
0207                     token_stack_.last().invertSignSecondArg();
0208                     token_index++;
0209                     continue;
0210                 } else {
0211                     errorIndex = token_index;
0212                     return -1;
0213                 }
0214                 break;
0215             case KCalcToken::TokenType::RIGHT_UNARY_FUNCTION_TYPE:
0216                 if (tokenCode == KCalcToken::TokenCode::MINUS) {
0217                     token_stack_.last().invertSignFirstArg();
0218                     token_index++;
0219                     continue;
0220                 } else if (tokenCode == KCalcToken::TokenCode::PLUS) {
0221                     token_index++;
0222                     continue;
0223                 }
0224                 break;
0225             case KCalcToken::TokenType::OPENING_PARENTHESES_TYPE:
0226                 if (tokenCode == KCalcToken::TokenCode::PLUS || tokenCode == KCalcToken::TokenCode::MINUS) {
0227                     token_stack_.push_back(KCalcToken(KNumber::Zero));
0228                 } else {
0229                     errorIndex = token_index;
0230                     return -1;
0231                 }
0232                 break;
0233             default:
0234                 break;
0235             }
0236 
0237             insert_Binary_Function_Token_In_Stack_(tokenBuffer.at(token_index));
0238             token_index++;
0239             break;
0240         case KCalcToken::TokenType::OPENING_PARENTHESES_TYPE:
0241             if (!token_stack_.isEmpty()) {
0242                 switch (token_stack_.last().getTokenType()) {
0243                 case KCalcToken::TokenType::KNUMBER_TYPE:
0244                 case KCalcToken::TokenType::LEFT_UNARY_FUNCTION_TYPE:
0245                 case KCalcToken::TokenType::CLOSING_PARENTHESES_TYPE:
0246                     insert_Binary_Function_Token_In_Stack_(multiplication_Token_);
0247                     break;
0248                 default:
0249                     break;
0250                 }
0251             }
0252             token_stack_.push_back(tokenBuffer.at(token_index));
0253             token_index++;
0254             break;
0255         case KCalcToken::TokenType::CLOSING_PARENTHESES_TYPE:
0256             if (token_stack_.isEmpty()) {
0257                 errorIndex = token_index;
0258                 return -1;
0259             }
0260             switch (token_stack_.last().getTokenType()) {
0261             case KCalcToken::TokenType::BINARY_FUNCTION_TYPE:
0262             case KCalcToken::TokenType::RIGHT_UNARY_FUNCTION_TYPE:
0263                 errorIndex = token_index;
0264                 return -1;
0265                 break;
0266             default:
0267                 reduce_Stack_();
0268                 break;
0269             }
0270             token_index++;
0271             break;
0272         default:
0273             break;
0274         }
0275     }
0276 
0277     qDebug() << "Done processing token list";
0278     // printStacks_();
0279 
0280     reduce_Stack_(/*toParentheses =*/false);
0281 
0282     qDebug() << "Done reducing final token stack";
0283 
0284     if (token_stack_.isEmpty()) {
0285         buffer_result_ = KNumber::Zero;
0286         return -2; // code for empthy calculation
0287     } else if (token_stack_.last().getKNumber() == KNumber::NaN) {
0288         error_ = true;
0289         buffer_result_ = token_stack_.last().getKNumber();
0290         token_stack_.clear();
0291         return -1;
0292     } else if (token_stack_.size() > 1) {
0293         error_ = true;
0294         buffer_result_ = KNumber::NaN;
0295         token_stack_.clear();
0296         return -1;
0297     } else {
0298         buffer_result_ = token_stack_.last().getKNumber();
0299         token_stack_.clear();
0300     }
0301 
0302     qDebug() << "Result: " << buffer_result_.toQString(12, -1);
0303 
0304     return 0;
0305 }
0306 
0307 int CalcEngine::insert_KNumber_Token_In_Stack_(const KCalcToken &token)
0308 {
0309     qDebug() << "Inserting KNumber Token in stack";
0310     // printStacks_();
0311     KCalcToken const *tokenFunction;
0312     KCalcToken const *tokenFirstArg;
0313 
0314     KCalcToken tokenToInsert = token;
0315 
0316     while (!token_stack_.isEmpty()) {
0317         if (token_stack_.last().isKNumber()) {
0318             insert_Binary_Function_Token_In_Stack_(multiplication_Token_);
0319             break;
0320         }
0321         if (token_stack_.last().isBinaryFunction() || token_stack_.last().isOpeningParentheses()) {
0322             break;
0323         }
0324         if (token_stack_.last().isLeftUnaryFunction()) {
0325             // never executed //
0326             break;
0327         }
0328         while (token_stack_.last().isRightUnaryFunction()) {
0329             tokenFunction = &token_stack_.last();
0330             tokenFirstArg = &tokenToInsert;
0331             KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0332             token_stack_.pop_back();
0333             tokenToInsert = KCalcToken(result);
0334 
0335             if (token_stack_.isEmpty()) {
0336                 break;
0337             }
0338         }
0339     }
0340     token_stack_.push_back(tokenToInsert);
0341     return 0;
0342 }
0343 
0344 int CalcEngine::insert_Binary_Function_Token_In_Stack_(const KCalcToken &token)
0345 {
0346     qDebug() << "Insert Binary Function Token in stack";
0347     // printStacks_();
0348     KCalcToken const *tokenFunction;
0349     KCalcToken const *tokenFirstArg;
0350     KCalcToken const *tokenSecondArg;
0351 
0352     if (token_stack_.isEmpty()) {
0353         return -1;
0354     }
0355 
0356     if (token_stack_.size() <= 2) {
0357         token_stack_.push_back(token);
0358         return 0;
0359     }
0360 
0361     if (token_stack_.at(token_stack_.size() - 2).isRightUnaryFunction() && token_stack_.last().isKNumber()) {
0362         tokenFunction = &token_stack_.at(token_stack_.size() - 2);
0363         tokenFirstArg = &token_stack_.last();
0364         KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0365         token_stack_.pop_back();
0366         token_stack_.pop_back();
0367         insert_KNumber_Token_In_Stack_(KCalcToken(result));
0368         if (token_stack_.size() <= 2) {
0369             token_stack_.push_back(token);
0370             return 0;
0371         } // else continue inserting
0372     }
0373 
0374     if (token_stack_.at(token_stack_.size() - 1).isKNumber() && token_stack_.at(token_stack_.size() - 2).isBinaryFunction()
0375         && token_stack_.at(token_stack_.size() - 3).isKNumber()) {
0376         if (token_stack_.size() > 3) {
0377             if (token_stack_.at(token_stack_.size() - 4).isRightUnaryFunction()) {
0378                 token_stack_.push_back(token);
0379                 return 0;
0380             }
0381         }
0382         if (token_stack_.at(token_stack_.size() - 2).getPriorityLevel() >= token.getPriorityLevel()) {
0383             tokenFunction = &token_stack_.at(token_stack_.size() - 2);
0384             tokenFirstArg = &token_stack_.at(token_stack_.size() - 3);
0385             tokenSecondArg = &token_stack_.at(token_stack_.size() - 1);
0386             KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber(), tokenSecondArg->getKNumber());
0387             token_stack_.pop_back();
0388             token_stack_.pop_back();
0389             token_stack_.last().updateToken(result);
0390             token_stack_.push_back(token);
0391             return 0;
0392         } else {
0393             token_stack_.push_back(token);
0394             return 0;
0395         }
0396     }
0397 
0398     token_stack_.push_back(token);
0399 
0400     return 0;
0401 }
0402 
0403 int CalcEngine::reduce_Stack_(bool toParentheses /*= true*/)
0404 {
0405     KCalcToken const *tokenFunction;
0406     KCalcToken const *tokenFirstArg;
0407     KCalcToken const *tokenSecondArg;
0408 
0409     while (token_stack_.size() > 1) {
0410         qDebug() << "Reducing at stack size: " << token_stack_.size();
0411         // printStacks_();
0412         if (token_stack_.last().isOpeningParentheses()) {
0413             token_stack_.pop_back();
0414             if (toParentheses) {
0415                 return 0;
0416             } else {
0417                 continue;
0418             }
0419         }
0420 
0421         if (token_stack_.last().isKNumber() && token_stack_.at(token_stack_.size() - 2).isOpeningParentheses()) {
0422             KNumber result = token_stack_.last().getKNumber();
0423             token_stack_.pop_back();
0424             token_stack_.pop_back();
0425             insert_KNumber_Token_In_Stack_(KCalcToken(result));
0426             if (toParentheses) {
0427                 return 0;
0428             } else {
0429                 continue;
0430             }
0431         }
0432 
0433         if (token_stack_.last().isKNumber() && token_stack_.at(token_stack_.size() - 2).isRightUnaryFunction()) {
0434             tokenFunction = &token_stack_.at(token_stack_.size() - 2);
0435             tokenFirstArg = &token_stack_.last();
0436             KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0437             token_stack_.pop_back();
0438             token_stack_.pop_back();
0439             insert_KNumber_Token_In_Stack_(KCalcToken(result));
0440             continue;
0441         }
0442 
0443         if (token_stack_.last().isLeftUnaryFunction() && token_stack_.at(token_stack_.size() - 2).isKNumber()) {
0444             // never executed
0445             tokenFunction = &token_stack_.last();
0446             tokenFirstArg = &token_stack_.at(token_stack_.size() - 2);
0447             KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0448             token_stack_.pop_back();
0449             token_stack_.last().updateToken(result);
0450             continue;
0451         }
0452 
0453         if (token_stack_.size() > 3) {
0454             if (token_stack_.at(token_stack_.size() - 3).isKNumber() && token_stack_.at(token_stack_.size() - 4).isRightUnaryFunction()) {
0455                 tokenFunction = &token_stack_.at(token_stack_.size() - 4);
0456                 tokenFirstArg = &token_stack_.at(token_stack_.size() - 3);
0457 
0458                 KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber());
0459 
0460                 token_stack_.removeAt(token_stack_.size() - 4);
0461                 token_stack_.replace(token_stack_.size() - 3, KCalcToken(result));
0462                 continue;
0463             }
0464 
0465             if (token_stack_.at(token_stack_.size() - 1).isKNumber() && token_stack_.at(token_stack_.size() - 2).isBinaryFunction()
0466                 && token_stack_.at(token_stack_.size() - 3).isBinaryFunction() && token_stack_.at(token_stack_.size() - 4).isKNumber()) {
0467                 if (token_stack_.at(token_stack_.size() - 2).getTokenCode() != KCalcToken::TokenCode::MINUS) {
0468                     return -1;
0469                 }
0470 
0471                 tokenFunction = &token_stack_.at(token_stack_.size() - 3);
0472                 tokenFirstArg = &token_stack_.at(token_stack_.size() - 4);
0473                 tokenSecondArg = &token_stack_.at(token_stack_.size() - 1);
0474                 KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber(), -tokenSecondArg->getKNumber());
0475 
0476                 token_stack_.pop_back();
0477                 token_stack_.pop_back();
0478                 token_stack_.pop_back();
0479                 token_stack_.last().updateToken(result);
0480                 continue;
0481             }
0482         }
0483 
0484         if (token_stack_.size() > 2) {
0485             if (token_stack_.last().isKNumber() && token_stack_.at(token_stack_.size() - 2).isBinaryFunction()
0486                 && token_stack_.at(token_stack_.size() - 3).isKNumber()) {
0487                 tokenSecondArg = &token_stack_.last();
0488                 tokenFunction = &token_stack_.at(token_stack_.size() - 2);
0489                 tokenFirstArg = &token_stack_.at(token_stack_.size() - 3);
0490 
0491                 KNumber result = tokenFunction->evaluate(tokenFirstArg->getKNumber(), tokenSecondArg->getKNumber());
0492 
0493                 token_stack_.pop_back();
0494                 token_stack_.pop_back();
0495                 token_stack_.last().updateToken(result);
0496                 continue;
0497             }
0498             if (token_stack_.at(token_stack_.size() - 1).isKNumber() && token_stack_.at(token_stack_.size() - 2).isBinaryFunction()
0499                 && token_stack_.at(token_stack_.size() - 3).isBinaryFunction()) {
0500                 if (token_stack_.at(token_stack_.size() - 2).getTokenCode() != KCalcToken::TokenCode::MINUS) {
0501                     return -1;
0502                 }
0503                 KNumber result = -token_stack_.last().getKNumber();
0504                 token_stack_.pop_back();
0505                 token_stack_.last().updateToken(result);
0506                 continue;
0507             }
0508         }
0509 
0510         if (token_stack_.at(token_stack_.size() - 1).isKNumber() && token_stack_.at(token_stack_.size() - 2).isBinaryFunction()) {
0511             if (token_stack_.at(token_stack_.size() - 2).getTokenCode() != KCalcToken::TokenCode::MINUS) {
0512                 return -1;
0513             }
0514             KNumber result = -token_stack_.last().getKNumber();
0515             token_stack_.pop_back();
0516             token_stack_.last().updateToken(result);
0517         }
0518 
0519         qDebug() << "Error at stack size = " << token_stack_.size();
0520         return -1;
0521     }
0522     return 0;
0523 }
0524 
0525 void CalcEngine::printStacks_()
0526 {
0527     int tokenStaskSize = token_stack_.size();
0528 
0529     qDebug() << "Printing current stack:";
0530 
0531     for (int i = 0; i < tokenStaskSize; i++) {
0532         if (token_stack_.at(i).isKNumber()) {
0533             qDebug() << "TokenStack at:" << i << " is KNumber   = " << (token_stack_.at(i).getKNumber()).toQString();
0534 
0535         } else {
0536             qDebug() << "TokenStack at:" << i << " is TokenCode = " << (token_stack_.at(i).getTokenCode());
0537         }
0538     }
0539 
0540     qDebug() << "Print current stack done";
0541 }
0542 
0543 KNumber CalcEngine::getResult()
0544 {
0545     return buffer_result_;
0546 }