diff --git a/kcalc_core.cpp b/kcalc_core.cpp index 5bdeefa..c64a075 100644 --- a/kcalc_core.cpp +++ b/kcalc_core.cpp @@ -1,924 +1,927 @@ /* Copyright (C) 2001 - 2013 Evan Teran evan.teran@gmail.com Copyright (C) 2003 - 2005 Klaus Niederkrueger kniederk@math.uni-koeln.de Copyright (C) 1996 - 2000 Bernd Johannes Wuebben wuebben@kde.org Copyright (C) 1995 Martin Bartlett This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "kcalc_core.h" #include "kcalc_settings.h" #include namespace { KNumber Deg2Rad(const KNumber &x) { return x * (KNumber::Pi() / KNumber(180)); } KNumber Gra2Rad(const KNumber &x) { return x * (KNumber::Pi() / KNumber(200)); } KNumber Rad2Deg(const KNumber &x) { return x * (KNumber(180) / KNumber::Pi()); } KNumber Rad2Gra(const KNumber &x) { return x * (KNumber(200) / KNumber::Pi()); } bool error_; KNumber ExecOr(const KNumber &left_op, const KNumber &right_op) { return left_op | right_op; } KNumber ExecXor(const KNumber &left_op, const KNumber &right_op) { return left_op ^ right_op; } KNumber ExecAnd(const KNumber &left_op, const KNumber &right_op) { return left_op & right_op; } KNumber ExecLsh(const KNumber &left_op, const KNumber &right_op) { return left_op << right_op; } KNumber ExecRsh(const KNumber &left_op, const KNumber &right_op) { return left_op >> right_op; } KNumber ExecAdd(const KNumber &left_op, const KNumber &right_op) { return left_op + right_op; } KNumber ExecSubtract(const KNumber &left_op, const KNumber &right_op) { return left_op - right_op; } KNumber ExecMultiply(const KNumber &left_op, const KNumber &right_op) { return left_op * right_op; } KNumber ExecDivide(const KNumber &left_op, const KNumber &right_op) { return left_op / right_op; } KNumber ExecMod(const KNumber &left_op, const KNumber &right_op) { return left_op % right_op; } KNumber ExecIntDiv(const KNumber &left_op, const KNumber &right_op) { return (left_op / right_op).integerPart(); } KNumber ExecBinom(const KNumber &left_op, const KNumber &right_op) { return left_op.bin(right_op); } KNumber ExecPower(const KNumber &left_op, const KNumber &right_op) { return left_op.pow(right_op); } KNumber ExecPwrRoot(const KNumber &left_op, const KNumber &right_op) { return left_op.pow(KNumber::One / right_op); } KNumber ExecAddP(const KNumber &left_op, const KNumber &right_op) { return left_op * (KNumber::One + right_op / KNumber(100)); } KNumber ExecSubP(const KNumber &left_op, const KNumber &right_op) { return left_op * (KNumber::One - right_op / KNumber(100)); } KNumber ExecMultiplyP(const KNumber &left_op, const KNumber &right_op) { return left_op * right_op / KNumber(100); } KNumber ExecDivideP(const KNumber &left_op, const KNumber &right_op) { return left_op * KNumber(100) / right_op; } // move a number into the interval [0,360) by adding multiples of 360 KNumber moveIntoDegInterval(const KNumber &num) { KNumber tmp_num = num - (num / KNumber(360)).integerPart() * KNumber(360); if (tmp_num < KNumber::Zero) return tmp_num + KNumber(360); return tmp_num; } // move a number into the interval [0,400) by adding multiples of 400 KNumber moveIntoGradInterval(const KNumber &num) { KNumber tmp_num = num - (num / KNumber(400)).integerPart() * KNumber(400); if (tmp_num < KNumber::Zero) return tmp_num + KNumber(400); return tmp_num; } typedef KNumber(*Arith)(const KNumber &, const KNumber &); typedef KNumber(*Prcnt)(const KNumber &, const KNumber &); struct operator_data { int precedence; // priority of operators in " enum Operation" Arith arith_ptr; Prcnt prcnt_ptr; }; // build precedence list const struct operator_data Operator[] = { { 0, nullptr, nullptr}, // FUNC_EQUAL { 0, nullptr, nullptr}, // FUNC_PERCENT { 0, nullptr, nullptr}, // FUNC_BRACKET { 1, ExecOr, nullptr}, // FUNC_OR { 2, ExecXor, nullptr}, // FUNC_XOR { 3, ExecAnd, nullptr}, // FUNC_AND { 4, ExecLsh, nullptr}, // FUNC_LSH { 4, ExecRsh, nullptr}, // FUNC_RSH { 5, ExecAdd, ExecAddP}, // FUNC_ADD { 5, ExecSubtract, ExecSubP}, // FUNC_SUBTRACT { 6, ExecMultiply, ExecMultiplyP}, // FUNC_MULTIPLY { 6, ExecDivide, ExecDivideP}, // FUNC_DIVIDE { 6, ExecMod, nullptr}, // FUNC_MOD { 6, ExecIntDiv, nullptr}, // FUNC_INTDIV { 7, ExecBinom, nullptr}, // FUNC_BINOM { 7, ExecPower, nullptr}, // FUNC_POWER { 7, ExecPwrRoot, nullptr} // FUNC_PWR_ROOT }; } CalcEngine::CalcEngine() - : only_update_operation_(false), repeat_mode_(false), percent_mode_(false) { + : only_update_operation_(false) + , percent_mode_(false) + , repeat_mode_(false) +{ last_number_ = KNumber::Zero; error_ = false; last_operation_ = FUNC_EQUAL; } KNumber CalcEngine::lastOutput(bool &error) const { error = error_; return last_number_; } void CalcEngine::ArcCosDeg(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } if (input.type() == KNumber::TYPE_INTEGER) { if (input == KNumber::One) { last_number_ = KNumber::Zero; return; } if (input == - KNumber::One) { last_number_ = KNumber(180); return; } if (input == KNumber::Zero) { last_number_ = KNumber(90); return; } } last_number_ = Rad2Deg(input.acos()); } void CalcEngine::ArcCosRad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } last_number_ = input.acos(); } void CalcEngine::ArcCosGrad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } if (input.type() == KNumber::TYPE_INTEGER) { if (input == KNumber::One) { last_number_ = KNumber::Zero; return; } if (input == - KNumber::One) { last_number_ = KNumber(200); return; } if (input == KNumber::Zero) { last_number_ = KNumber(100); return; } } last_number_ = Rad2Gra(input.acos()); } void CalcEngine::ArcSinDeg(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } if (input.type() == KNumber::TYPE_INTEGER) { if (input == KNumber::One) { last_number_ = KNumber(90); return; } if (input == - KNumber::One) { last_number_ = KNumber(-90); return; } if (input == KNumber::Zero) { last_number_ = KNumber::Zero; return; } } last_number_ = Rad2Deg(input.asin()); } void CalcEngine::ArcSinRad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } last_number_ = input.asin(); } void CalcEngine::ArcSinGrad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR || input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } if (input.type() == KNumber::TYPE_INTEGER) { if (input == KNumber::One) { last_number_ = KNumber(100); return; } if (input == - KNumber::One) { last_number_ = KNumber(-100); return; } if (input == KNumber::Zero) { last_number_ = KNumber::Zero; return; } } last_number_ = Rad2Gra(input.asin()); } void CalcEngine::ArcTangensDeg(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber(90); if (input == KNumber::NegInfinity) last_number_ = KNumber(-90); return; } last_number_ = Rad2Deg(input.atan()); } void CalcEngine::ArcTangensRad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::Pi() / KNumber(2); if (input == KNumber::NegInfinity) last_number_ = -KNumber::Pi() / KNumber(2); return; } last_number_ = input.atan(); } void CalcEngine::ArcTangensGrad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber(100); if (input == KNumber::NegInfinity) last_number_ = KNumber(-100); return; } last_number_ = Rad2Gra(input.atan()); } void CalcEngine::AreaCosHyp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::PosInfinity; if (input == KNumber::NegInfinity) last_number_ = KNumber::NaN; return; } if (input < KNumber::One) { last_number_ = KNumber::NaN; return; } if (input == KNumber::One) { last_number_ = KNumber::Zero; return; } last_number_ = input.acosh(); } void CalcEngine::AreaSinHyp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::PosInfinity; if (input == KNumber::NegInfinity) last_number_ = KNumber::NegInfinity; return; } if (input == KNumber::Zero) { last_number_ = KNumber::Zero; return; } last_number_ = input.asinh(); } void CalcEngine::AreaTangensHyp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } if (input < -KNumber::One || input > KNumber::One) { last_number_ = KNumber::NaN; return; } if (input == KNumber::One) { last_number_ = KNumber::PosInfinity; return; } if (input == - KNumber::One) { last_number_ = KNumber::NegInfinity; return; } last_number_ = input.atanh(); } void CalcEngine::Complement(const KNumber &input) { if (input.type() != KNumber::TYPE_INTEGER) { last_number_ = KNumber::NaN; return; } last_number_ = ~input; } void CalcEngine::CosDeg(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } KNumber trunc_input = moveIntoDegInterval(input); if (trunc_input.type() == KNumber::TYPE_INTEGER) { KNumber mult = trunc_input / KNumber(90); if (mult.type() == KNumber::TYPE_INTEGER) { if (mult == KNumber::Zero) last_number_ = KNumber::One; else if (mult == KNumber::One) last_number_ = KNumber::Zero; else if (mult == KNumber(2)) last_number_ = KNumber::NegOne; else if (mult == KNumber(3)) last_number_ = KNumber::Zero; else qDebug() << "Something wrong in CalcEngine::CosDeg"; return; } } trunc_input = Deg2Rad(trunc_input); last_number_ = trunc_input.cos(); } void CalcEngine::CosRad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } last_number_ = input.cos(); } void CalcEngine::CosGrad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } KNumber trunc_input = moveIntoGradInterval(input); if (trunc_input.type() == KNumber::TYPE_INTEGER) { KNumber mult = trunc_input / KNumber(100); if (mult.type() == KNumber::TYPE_INTEGER) { if (mult == KNumber::Zero) last_number_ = KNumber::One; else if (mult == KNumber::One) last_number_ = KNumber::Zero; else if (mult == KNumber(2)) last_number_ = KNumber::NegOne; else if (mult == KNumber(3)) last_number_ = KNumber::Zero; else qDebug() << "Something wrong in CalcEngine::CosGrad"; return; } } trunc_input = Gra2Rad(trunc_input); last_number_ = trunc_input.cos(); } void CalcEngine::CosHyp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::PosInfinity; // YES, this should be *positive* infinity. We mimic the behavior of // libc which says the following for cosh // // "If x is positive infinity or negative infinity, positive infinity is returned." if (input == KNumber::NegInfinity) last_number_ = KNumber::PosInfinity; return; } last_number_ = input.cosh(); } void CalcEngine::Cube(const KNumber &input) { last_number_ = input * input * input; } void CalcEngine::CubeRoot(const KNumber &input) { last_number_ = input.cbrt(); } void CalcEngine::Exp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::PosInfinity; if (input == KNumber::NegInfinity) last_number_ = KNumber::Zero; return; } last_number_ = KNumber::Euler().pow(input); } void CalcEngine::Exp10(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::PosInfinity; if (input == KNumber::NegInfinity) last_number_ = KNumber::Zero; return; } last_number_ = KNumber(10).pow(input); } void CalcEngine::Factorial(const KNumber &input) { if (input == KNumber::PosInfinity) return; if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) { error_ = true; last_number_ = KNumber::NaN; return; } last_number_ = input.integerPart().factorial(); } void CalcEngine::Gamma(const KNumber &input) { if (input == KNumber::PosInfinity) return; if (input < KNumber::Zero || input.type() == KNumber::TYPE_ERROR) { error_ = true; last_number_ = KNumber::NaN; return; } last_number_ = input.tgamma(); } void CalcEngine::InvertSign(const KNumber &input) { last_number_ = -input; } void CalcEngine::Ln(const KNumber &input) { if (input < KNumber::Zero) last_number_ = KNumber::NaN; else if (input == KNumber::Zero) last_number_ = KNumber::NegInfinity; else if (input == KNumber::One) last_number_ = KNumber::Zero; else { last_number_ = input.ln(); } } void CalcEngine::Log10(const KNumber &input) { if (input < KNumber::Zero) last_number_ = KNumber::NaN; else if (input == KNumber::Zero) last_number_ = KNumber::NegInfinity; else if (input == KNumber::One) last_number_ = KNumber::Zero; else { last_number_ = input.log10(); } } void CalcEngine::ParenClose(KNumber input) { // evaluate stack until corresponding opening bracket while (!stack_.isEmpty()) { Node tmp_node = stack_.pop(); if (tmp_node.operation == FUNC_BRACKET) break; input = evalOperation(tmp_node.number, tmp_node.operation, input); } last_number_ = input; return; } void CalcEngine::ParenOpen(const KNumber &input) { enterOperation(input, FUNC_BRACKET); } void CalcEngine::Reciprocal(const KNumber &input) { last_number_ = KNumber::One / input; } void CalcEngine::SinDeg(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } KNumber trunc_input = moveIntoDegInterval(input); if (trunc_input.type() == KNumber::TYPE_INTEGER) { KNumber mult = trunc_input / KNumber(90); if (mult.type() == KNumber::TYPE_INTEGER) { if (mult == KNumber::Zero) last_number_ = KNumber::Zero; else if (mult == KNumber::One) last_number_ = KNumber::One; else if (mult == KNumber(2)) last_number_ = KNumber::Zero; else if (mult == KNumber(3)) last_number_ = KNumber::NegOne; else qDebug() << "Something wrong in CalcEngine::SinDeg"; return; } } trunc_input = Deg2Rad(trunc_input); last_number_ = trunc_input.sin(); } void CalcEngine::SinRad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } last_number_ = input.sin(); } void CalcEngine::SinGrad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } KNumber trunc_input = moveIntoGradInterval(input); if (trunc_input.type() == KNumber::TYPE_INTEGER) { KNumber mult = trunc_input / KNumber(100); if (mult.type() == KNumber::TYPE_INTEGER) { if (mult == KNumber::Zero) last_number_ = KNumber::Zero; else if (mult == KNumber::One) last_number_ = KNumber::One; else if (mult == KNumber(2)) last_number_ = KNumber::Zero; else if (mult == KNumber(3)) last_number_ = KNumber::NegOne; else qDebug() << "Something wrong in CalcEngine::SinGrad"; return; } } trunc_input = Gra2Rad(trunc_input); last_number_ = trunc_input.sin(); } void CalcEngine::SinHyp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::PosInfinity; if (input == KNumber::NegInfinity) last_number_ = KNumber::NegInfinity; return; } last_number_ = input.sinh(); } void CalcEngine::Square(const KNumber &input) { last_number_ = input * input; } void CalcEngine::SquareRoot(const KNumber &input) { last_number_ = input.sqrt(); } void CalcEngine::StatClearAll(const KNumber &input) { Q_UNUSED(input); stats.clearAll(); } void CalcEngine::StatCount(const KNumber &input) { Q_UNUSED(input); last_number_ = KNumber(stats.count()); } void CalcEngine::StatDataNew(const KNumber &input) { stats.enterData(input); last_number_ = KNumber(stats.count()); } void CalcEngine::StatDataDel(const KNumber &input) { Q_UNUSED(input); stats.clearLast(); last_number_ = KNumber(stats.count()); } void CalcEngine::StatMean(const KNumber &input) { Q_UNUSED(input); last_number_ = stats.mean(); error_ = stats.error(); } void CalcEngine::StatMedian(const KNumber &input) { Q_UNUSED(input); last_number_ = stats.median(); error_ = stats.error(); } void CalcEngine::StatStdDeviation(const KNumber &input) { Q_UNUSED(input); last_number_ = stats.std(); error_ = stats.error(); } void CalcEngine::StatStdSample(const KNumber &input) { Q_UNUSED(input); last_number_ = stats.sample_std(); error_ = stats.error(); } void CalcEngine::StatSum(const KNumber &input) { Q_UNUSED(input); last_number_ = stats.sum(); } void CalcEngine::StatSumSquares(const KNumber &input) { Q_UNUSED(input); last_number_ = stats.sum_of_squares(); error_ = stats.error(); } void CalcEngine::TangensDeg(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } SinDeg(input); KNumber arg1 = last_number_; CosDeg(input); KNumber arg2 = last_number_; last_number_ = arg1 / arg2; } void CalcEngine::TangensRad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } SinRad(input); KNumber arg1 = last_number_; CosRad(input); KNumber arg2 = last_number_; last_number_ = arg1 / arg2; } void CalcEngine::TangensGrad(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { last_number_ = KNumber::NaN; return; } SinGrad(input); KNumber arg1 = last_number_; CosGrad(input); KNumber arg2 = last_number_; last_number_ = arg1 / arg2; } void CalcEngine::TangensHyp(const KNumber &input) { if (input.type() == KNumber::TYPE_ERROR) { if (input == KNumber::NaN) last_number_ = KNumber::NaN; if (input == KNumber::PosInfinity) last_number_ = KNumber::One; if (input == KNumber::NegInfinity) last_number_ = KNumber::NegOne; return; } last_number_ = input.tanh(); } KNumber CalcEngine::evalOperation(const KNumber &arg1, Operation operation, const KNumber &arg2) { if (!percent_mode_ || Operator[operation].prcnt_ptr == nullptr) { return (Operator[operation].arith_ptr)(arg1, arg2); } else { percent_mode_ = false; return (Operator[operation].prcnt_ptr)(arg1, arg2); } } void CalcEngine::enterOperation(const KNumber &number, Operation func) { Node tmp_node; if (func == FUNC_BRACKET) { tmp_node.number = KNumber::Zero; tmp_node.operation = FUNC_BRACKET; stack_.push(tmp_node); return; } if (func == FUNC_PERCENT) { percent_mode_ = true; } tmp_node.number = number; tmp_node.operation = func; if (KCalcSettings::repeatLastOperation()) { if (func != FUNC_EQUAL && func != FUNC_PERCENT) { last_operation_ = tmp_node.operation; repeat_mode_ = false; } if (func == FUNC_EQUAL || func == FUNC_PERCENT) { if (!repeat_mode_) { repeat_mode_ = last_operation_ != FUNC_EQUAL; last_repeat_number_ = number; } else { Node repeat_node; repeat_node.operation = last_operation_; repeat_node.number = number; tmp_node.number = last_repeat_number_; stack_.push(repeat_node); } } } if (getOnlyUpdateOperation() && !stack_.isEmpty() && !(func == FUNC_EQUAL || func == FUNC_PERCENT)) stack_.top().operation = func; else stack_.push(tmp_node); evalStack(); } bool CalcEngine::evalStack() { // this should never happen Q_ASSERT(!stack_.isEmpty()); Node tmp_node = stack_.pop(); while (! stack_.isEmpty()) { Node tmp_node2 = stack_.pop(); if (Operator[tmp_node.operation].precedence <= Operator[tmp_node2.operation].precedence) { if (tmp_node2.operation == FUNC_BRACKET) continue; const KNumber tmp_result = evalOperation(tmp_node2.number, tmp_node2.operation, tmp_node.number); tmp_node.number = tmp_result; } else { stack_.push(tmp_node2); break; } } if (tmp_node.operation != FUNC_EQUAL && tmp_node.operation != FUNC_PERCENT) stack_.push(tmp_node); last_number_ = tmp_node.number; return true; } void CalcEngine::Reset() { percent_mode_ = false; repeat_mode_ = false; last_operation_ = FUNC_EQUAL; error_ = false; last_number_ = KNumber::Zero; only_update_operation_ = false; stack_.clear(); } void CalcEngine::setOnlyUpdateOperation(bool update) { only_update_operation_ = update; } bool CalcEngine::getOnlyUpdateOperation() const { return only_update_operation_; } diff --git a/kcalc_core.h b/kcalc_core.h index c91a9fd..73c2af1 100644 --- a/kcalc_core.h +++ b/kcalc_core.h @@ -1,156 +1,156 @@ /* Copyright (C) 2001 - 2013 Evan Teran evan.teran@gmail.com Copyright (C) 1996 - 2000 Bernd Johannes Wuebben wuebben@kde.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KCALC_CORE_H_ #define KCALC_CORE_H_ #include #include "stats.h" #include "knumber.h" class CalcEngine { public: // operations that can be stored in calculation stack enum Operation { FUNC_EQUAL, FUNC_PERCENT, FUNC_BRACKET, FUNC_OR, FUNC_XOR, FUNC_AND, FUNC_LSH, FUNC_RSH, FUNC_ADD, FUNC_SUBTRACT, FUNC_MULTIPLY, FUNC_DIVIDE, FUNC_MOD, FUNC_INTDIV, FUNC_BINOM, FUNC_POWER, FUNC_PWR_ROOT }; CalcEngine(); KNumber lastOutput(bool &error) const; void enterOperation(const KNumber &num, Operation func); void ArcCosDeg(const KNumber &input); void ArcCosRad(const KNumber &input); void ArcCosGrad(const KNumber &input); void ArcSinDeg(const KNumber &input); void ArcSinRad(const KNumber &input); void ArcSinGrad(const KNumber &input); void ArcTangensDeg(const KNumber &input); void ArcTangensRad(const KNumber &input); void ArcTangensGrad(const KNumber &input); void AreaCosHyp(const KNumber &input); void AreaSinHyp(const KNumber &input); void AreaTangensHyp(const KNumber &input); void Complement(const KNumber &input); void CosDeg(const KNumber &input); void CosRad(const KNumber &input); void CosGrad(const KNumber &input); void CosHyp(const KNumber &input); void Cube(const KNumber &input); void CubeRoot(const KNumber &input); void Exp(const KNumber &input); void Exp10(const KNumber &input); void Factorial(const KNumber &input); void Gamma(const KNumber &input); void InvertSign(const KNumber &input); void Ln(const KNumber &input); void Log10(const KNumber &input); void ParenClose(KNumber input); void ParenOpen(const KNumber &input); void Reciprocal(const KNumber &input); void SinDeg(const KNumber &input); void SinGrad(const KNumber &input); void SinRad(const KNumber &input); void SinHyp(const KNumber &input); void Square(const KNumber &input); void SquareRoot(const KNumber &input); void StatClearAll(const KNumber &input); void StatCount(const KNumber &input); void StatDataNew(const KNumber &input); void StatDataDel(const KNumber &input); void StatMean(const KNumber &input); void StatMedian(const KNumber &input); void StatStdDeviation(const KNumber &input); void StatStdSample(const KNumber &input); void StatSum(const KNumber &input); void StatSumSquares(const KNumber &input); void TangensDeg(const KNumber &input); void TangensRad(const KNumber &input); void TangensGrad(const KNumber &input); void TangensHyp(const KNumber &input); void Reset(); void setOnlyUpdateOperation(bool update); bool getOnlyUpdateOperation() const; private: KStats stats; struct Node { KNumber number; Operation operation; }; // Stack holds all operations and numbers that have not yet been // processed, e.g. user types "2+3*", the calculation can not be // executed, because "*" has a higher precedence than "+", so we // need to wait for the next number. // // In the stack this would be stored as ((2,+),(3,*),...) // // "enterOperation": If the introduced Operation has lower priority // than the preceding operations in the stack, then we can start to // evaluate the stack (with "evalStack"). Otherwise we append the new // Operation and number to the stack. // // E.g. "2*3+" evaluates to "6+", but "2+3*" can not be evaluated // yet. // // We also take care of brackets, by writing a marker "FUNC_BRACKET" // into the stack, each time the user opens one. When a bracket is // closed, everything in the stack is evaluated until the first // marker "FUNC_BRACKET" found. QStack stack_; KNumber last_number_; Operation last_operation_; KNumber last_repeat_number_; - bool repeat_mode_; bool only_update_operation_; bool percent_mode_; + bool repeat_mode_; bool evalStack(); KNumber evalOperation(const KNumber &arg1, Operation operation, const KNumber &arg2); }; #endif