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 }