diff options
Diffstat (limited to 'kcalc/kcalc_core.cpp')
-rw-r--r-- | kcalc/kcalc_core.cpp | 1004 |
1 files changed, 1004 insertions, 0 deletions
diff --git a/kcalc/kcalc_core.cpp b/kcalc/kcalc_core.cpp new file mode 100644 index 0000000..4270895 --- /dev/null +++ b/kcalc/kcalc_core.cpp @@ -0,0 +1,1004 @@ +/* + kCalculator, a scientific calculator for the X window system using the + Qt widget libraries, available at no cost at http://www.troll.no + + The stack engine contained in this file was take from + Martin Bartlett's xfrmcalc + + portions: Copyright (C) 2003-2006 Klaus Niederkrueger + + portions: Copyright (C) 1996 Bernd Johannes Wuebben + wuebben@math.cornell.edu + + portions: 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + + +#if defined(_ISOC99_SOURCE) + #include <cassert> + #include <cstdio> + #include <climits> + #include <csignal> + #include <cerrno> + #include <cstring> + using namespace std; +#else + #include <limits.h> + #include <stdio.h> + #include <assert.h> + #include <signal.h> + #include <errno.h> + #include <string.h> +#endif + +#include <config.h> +#include "kcalc_core.h" +#include <stdlib.h> +#include <klocale.h> +#include <kmessagebox.h> +#include "kcalctype.h" + +#ifndef HAVE_FUNC_ISINF + #ifdef HAVE_IEEEFP_H + #include <ieeefp.h> + #else + #include <math.h> + #endif + +#undef isinf +int isinf(double x) +{ +#ifdef _HPUX_SOURCE +return !isfinite(x) && x == x; +#else +return !finite(x) && x==x; +#endif +} + +#endif + + +static void fpe_handler(int fpe_parm) +{ + UNUSED(fpe_parm); + // display_error = true; + //tmp_number = 0L; +} + + +static bool _error; + +static KNumber ExecOr(const KNumber & left_op, const KNumber & right_op) +{ + return (left_op | right_op); +} + +static KNumber ExecXor(const KNumber & left_op, const KNumber & right_op) +{ + return (left_op | right_op) - (left_op & right_op); +} + +static KNumber ExecAnd(const KNumber & left_op, const KNumber & right_op) +{ + return (left_op & right_op); +} + +static KNumber ExecLsh(const KNumber & left_op, const KNumber & right_op) +{ + return left_op << right_op; +} + +static KNumber ExecRsh(const KNumber & left_op, const KNumber & right_op) +{ + return left_op >> right_op; +} + +static KNumber ExecAdd(const KNumber & left_op, const KNumber & right_op) +{ + return left_op + right_op; +} + +static KNumber ExecSubtract(const KNumber & left_op, const KNumber & right_op) +{ + return left_op - right_op; +} + +static KNumber ExecMultiply(const KNumber & left_op, const KNumber & right_op) +{ + return left_op * right_op; +} + +static KNumber ExecDivide(const KNumber & left_op, const KNumber & right_op) +{ + return left_op / right_op; +} + +static KNumber ExecMod(const KNumber & left_op, const KNumber & right_op) +{ + return left_op % right_op; +} + +static KNumber ExecIntDiv(const KNumber & left_op, const KNumber & right_op) +{ + return (left_op / right_op).integerPart(); +} + +bool isoddint(const KNumber & input) +{ + if (input.type() != KNumber::IntegerType) return false; + // Routine to check if KNumber is an Odd integer + return ( (input / KNumber(2)).type() == KNumber::IntegerType); +} + +static KNumber ExecPower(const KNumber & left_op, const KNumber & right_op) +{ + return left_op.power(right_op); +} + +static KNumber ExecPwrRoot(const KNumber & left_op, const KNumber & right_op) +{ + return left_op.power(KNumber::One / right_op); +} + +static KNumber ExecAddP(const KNumber & left_op, const KNumber & right_op) +{ + return left_op * (KNumber::One + right_op/KNumber(100)); +} + +static KNumber ExecSubP(const KNumber & left_op, const KNumber & right_op) +{ + return left_op * (KNumber::One - right_op/KNumber(100)); +} + +static KNumber ExecMultiplyP(const KNumber & left_op, const KNumber & right_op) +{ + return left_op * right_op / KNumber(100); +} + +static KNumber ExecDivideP(const KNumber & left_op, const KNumber & right_op) +{ + return left_op * KNumber(100) / right_op; +} + + +// build precedence list +const struct operator_data CalcEngine::Operator[] = { + { 0, NULL, NULL}, // FUNC_EQUAL + { 0, NULL, NULL}, // FUNC_PERCENT + { 0, NULL, NULL}, // FUNC_BRACKET + { 1, ExecOr, NULL}, // FUNC_OR + { 2, ExecXor, NULL}, // FUNC_XOR + { 3, ExecAnd, NULL}, // FUNC_AND + { 4, ExecLsh, NULL}, // FUNC_LSH + { 4, ExecRsh, NULL}, // FUNC_RSH + { 5, ExecAdd, ExecAddP}, // FUNC_ADD + { 5, ExecSubtract, ExecSubP}, // FUNC_SUBTRACT + { 6, ExecMultiply, ExecMultiplyP}, // FUNC_MULTIPLY + { 6, ExecDivide, ExecDivideP}, // FUNC_DIVIDE + { 6, ExecMod, NULL}, // FUNC_MOD + { 6, ExecIntDiv, NULL}, // FUNC_INTDIV + { 7, ExecPower, NULL}, // FUNC_POWER + { 7, ExecPwrRoot, NULL} // FUNC_PWR_ROOT +}; + + +CalcEngine::CalcEngine() + : _percent_mode(false) +{ + // + // Basic initialization involves initializing the calcultion + // stack, and setting up the floating point excetion signal + // handler to trap the errors that the code can/has not been + // written to trap. + // + + struct sigaction fpe_trap; + + sigemptyset(&fpe_trap.sa_mask); + fpe_trap.sa_handler = &fpe_handler; +#ifdef SA_RESTART + fpe_trap.sa_flags = SA_RESTART; +#endif + sigaction(SIGFPE, &fpe_trap, NULL); + + _last_number = KNumber::Zero; + _error = false; +} + +KNumber CalcEngine::lastOutput(bool &error) const +{ + error = _error; + return _last_number; +} + +void CalcEngine::ArcCosDeg(KNumber input) +{ + if (input.type() == KNumber::SpecialType || + input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + + if (input.type() == KNumber::IntegerType) { + 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; + } + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = Rad2Deg(KNumber(double(ACOS(tmp_num)))); +} + +void CalcEngine::ArcCosRad(KNumber input) +{ + if (input.type() == KNumber::SpecialType || + input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(ACOS(tmp_num))); +} + +void CalcEngine::ArcCosGrad(KNumber input) +{ + if (input.type() == KNumber::SpecialType || + input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + if (input.type() == KNumber::IntegerType) { + 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; + } + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = Rad2Gra(KNumber(double(ACOS(tmp_num)))); +} + +void CalcEngine::ArcSinDeg(KNumber input) +{ + if (input.type() == KNumber::SpecialType || + input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + if (input.type() == KNumber::IntegerType) { + 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(0); + return; + } + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = Rad2Deg(KNumber(double(ASIN(tmp_num)))); +} + +void CalcEngine::ArcSinRad(KNumber input) +{ + if (input.type() == KNumber::SpecialType || + input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(ASIN(tmp_num))); +} + +void CalcEngine::ArcSinGrad(KNumber input) +{ + if (input.type() == KNumber::SpecialType || + input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + if (input.type() == KNumber::IntegerType) { + 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(0); + return; + } + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = Rad2Gra(KNumber(double(ASIN(tmp_num)))); +} + +void CalcEngine::ArcTangensDeg(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber(90); + if (input == KNumber("-inf")) _last_number = KNumber(-90); + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = Rad2Deg(KNumber(double(ATAN(tmp_num)))); +} + +void CalcEngine::ArcTangensRad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) + _last_number = KNumber::Pi/KNumber(2); + if (input == KNumber("-inf")) + _last_number = -KNumber::Pi/KNumber(2); + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(ATAN(tmp_num))); +} + +void CalcEngine::ArcTangensGrad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber(100); + if (input == KNumber("-inf")) _last_number = KNumber(-100); + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = Rad2Gra(KNumber(double(ATAN(tmp_num)))); +} + +void CalcEngine::AreaCosHyp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber("nan"); + return; + } + + if (input < KNumber::One) { + _last_number = KNumber("nan"); + return; + } + if (input == KNumber::One) { + _last_number = KNumber::Zero; + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(ACOSH(tmp_num))); +} + +void CalcEngine::AreaSinHyp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber("-inf"); + return; + } + + if (input == KNumber::Zero) { + _last_number = KNumber::Zero; + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(ASINH(tmp_num))); +} + +void CalcEngine::AreaTangensHyp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + if (input < -KNumber::One || input > KNumber::One) { + _last_number = KNumber("nan"); + return; + } + if (input == KNumber::One) { + _last_number = KNumber("inf"); + return; + } + if (input == - KNumber::One) { + _last_number = KNumber("-inf"); + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(ATANH(tmp_num))); +} + +void CalcEngine::Complement(KNumber input) +{ + if (input.type() != KNumber::IntegerType) + { + _last_number = KNumber("nan"); + return; + } + _last_number = - input - KNumber::One; +} + + + +// move a number into the interval [0,360) by adding multiples of 360 +static KNumber const moveIntoDegInterval(KNumber const &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 +static KNumber const moveIntoGradInterval(KNumber const &num) +{ + KNumber tmp_num = num - (num/KNumber(400)).integerPart() * KNumber(400); + if(tmp_num < KNumber::Zero) + return tmp_num + KNumber(400); + return tmp_num; +} + + +void CalcEngine::CosDeg(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + KNumber trunc_input = moveIntoDegInterval(input); + if (trunc_input.type() == KNumber::IntegerType) { + KNumber mult = trunc_input/KNumber(90); + if (mult.type() == KNumber::IntegerType) { + if (mult == KNumber::Zero) + _last_number = 1; + else if (mult == KNumber(1)) + _last_number = 0; + else if (mult == KNumber(2)) + _last_number = -1; + else if (mult == KNumber(3)) + _last_number = 0; + else qDebug("Something wrong in CalcEngine::CosDeg\n"); + return; + } + } + trunc_input = Deg2Rad(trunc_input); + + CALCAMNT tmp_num = static_cast<double>(trunc_input); + _last_number = KNumber(double(COS(tmp_num))); +} + +void CalcEngine::CosRad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(COS(tmp_num))); +} + +void CalcEngine::CosGrad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + KNumber trunc_input = moveIntoGradInterval(input); + if (trunc_input.type() == KNumber::IntegerType) { + KNumber mult = trunc_input/KNumber(100); + if (mult.type() == KNumber::IntegerType) { + if (mult == KNumber::Zero) + _last_number = 1; + else if (mult == KNumber(1)) + _last_number = 0; + else if (mult == KNumber(2)) + _last_number = -1; + else if (mult == KNumber(3)) + _last_number = 0; + else qDebug("Something wrong in CalcEngine::CosGrad\n"); + return; + } + } + trunc_input = Gra2Rad(trunc_input); + + CALCAMNT tmp_num = static_cast<double>(trunc_input); + _last_number = KNumber(double(COS(tmp_num))); +} + +void CalcEngine::CosHyp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber("inf"); + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(COSH(tmp_num))); +} + +void CalcEngine::Cube(KNumber input) +{ + _last_number = input*input*input; +} + +void CalcEngine::CubeRoot(KNumber input) +{ + _last_number = input.cbrt(); +} + +void CalcEngine::Exp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber::Zero; + return; + } + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(EXP(tmp_num))); +} + +void CalcEngine::Exp10(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber::Zero; + return; + } + _last_number = KNumber(10).power(input); +} + + +static KNumber _factorial(KNumber input) +{ + KNumber tmp_amount = input; + + // don't do recursive factorial, + // because large numbers lead to + // stack overflows + while (tmp_amount > KNumber::One) + { + tmp_amount -= KNumber::One; + + input = tmp_amount * input; + + } + + if (tmp_amount < KNumber::One) + return KNumber::One; + return input; +} + + +void CalcEngine::Factorial(KNumber input) +{ + if (input == KNumber("inf")) return; + if (input < KNumber::Zero || input.type() == KNumber::SpecialType) + { + _error = true; + _last_number = KNumber("nan"); + return; + } + KNumber tmp_amount = input.integerPart(); + + _last_number = _factorial(tmp_amount); +} + +void CalcEngine::InvertSign(KNumber input) +{ + _last_number = -input; +} + +void CalcEngine::Ln(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber("nan"); + return; + } + if (input < KNumber::Zero) + _last_number = KNumber("nan"); + else if (input == KNumber::Zero) + _last_number = KNumber("-inf"); + else if (input == KNumber::One) + _last_number = 0; + else { + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(LN(tmp_num))); + } +} + +void CalcEngine::Log10(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber("nan"); + return; + } + if (input < KNumber::Zero) + _last_number = KNumber("nan"); + else if (input == KNumber::Zero) + _last_number = KNumber("-inf"); + else if (input == KNumber::One) + _last_number = 0; + else { + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(LOG_TEN(tmp_num))); + } +} + +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(KNumber input) +{ + enterOperation(input, FUNC_BRACKET); +} + +void CalcEngine::Reciprocal(KNumber input) +{ + _last_number = KNumber::One/input; +} + + +void CalcEngine::SinDeg(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + KNumber trunc_input = moveIntoDegInterval(input); + if (trunc_input.type() == KNumber::IntegerType) { + KNumber mult = trunc_input/KNumber(90); + if (mult.type() == KNumber::IntegerType) { + if (mult == KNumber::Zero) + _last_number = 0; + else if (mult == KNumber(1)) + _last_number = 1; + else if (mult == KNumber(2)) + _last_number = 0; + else if (mult == KNumber(3)) + _last_number = -1; + else qDebug("Something wrong in CalcEngine::SinDeg\n"); + return; + } + } + trunc_input = Deg2Rad(trunc_input); + + CALCAMNT tmp_num = static_cast<double>(trunc_input); + _last_number = KNumber(double(SIN(tmp_num))); +} + +void CalcEngine::SinRad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(SIN(tmp_num))); +} + +void CalcEngine::SinGrad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + KNumber trunc_input = moveIntoGradInterval(input); + if (trunc_input.type() == KNumber::IntegerType) { + KNumber mult = trunc_input/KNumber(100); + if (mult.type() == KNumber::IntegerType) { + if (mult == KNumber::Zero) + _last_number = 0; + else if (mult == KNumber(1)) + _last_number = 1; + else if (mult == KNumber(2)) + _last_number = 0; + else if (mult == KNumber(3)) + _last_number = -1; + else qDebug("Something wrong in CalcEngine::SinGrad\n"); + return; + } + } + + trunc_input = Gra2Rad(trunc_input); + + CALCAMNT tmp_num = static_cast<double>(trunc_input); + _last_number = KNumber(double(SIN(tmp_num))); +} + +void CalcEngine::SinHyp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber("inf"); + if (input == KNumber("-inf")) _last_number = KNumber("-inf"); + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(SINH(tmp_num))); +} + +void CalcEngine::Square(KNumber input) +{ + _last_number = input*input; +} + +void CalcEngine::SquareRoot(KNumber input) +{ + _last_number = input.sqrt(); +} + +void CalcEngine::StatClearAll(KNumber input) +{ + UNUSED(input); + stats.clearAll(); +} + +void CalcEngine::StatCount(KNumber input) +{ + UNUSED(input); + _last_number = KNumber(stats.count()); +} + +void CalcEngine::StatDataNew(KNumber input) +{ + stats.enterData(input); + _last_number = KNumber(stats.count()); +} + +void CalcEngine::StatDataDel(KNumber input) +{ + UNUSED(input); + stats.clearLast(); + _last_number = KNumber::Zero; +} + +void CalcEngine::StatMean(KNumber input) +{ + UNUSED(input); + _last_number = stats.mean(); + + _error = stats.error(); +} + +void CalcEngine::StatMedian(KNumber input) +{ + UNUSED(input); + _last_number = stats.median(); + + _error = stats.error(); +} + +void CalcEngine::StatStdDeviation(KNumber input) +{ + UNUSED(input); + _last_number = stats.std(); + + _error = stats.error(); +} + +void CalcEngine::StatStdSample(KNumber input) +{ + UNUSED(input); + _last_number = stats.sample_std(); + + _error = stats.error(); +} + +void CalcEngine::StatSum(KNumber input) +{ + UNUSED(input); + _last_number = stats.sum(); +} + +void CalcEngine::StatSumSquares(KNumber input) +{ + UNUSED(input); + _last_number = stats.sum_of_squares(); + + _error = stats.error(); +} + +void CalcEngine::TangensDeg(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + SinDeg(input); + KNumber arg1 = _last_number; + CosDeg(input); + KNumber arg2 = _last_number; + _last_number = arg1 / arg2; +} + +void CalcEngine::TangensRad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + SinRad(input); + KNumber arg1 = _last_number; + CosRad(input); + KNumber arg2 = _last_number; + _last_number = arg1 / arg2; +} + +void CalcEngine::TangensGrad(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + _last_number = KNumber("nan"); + return; + } + + SinGrad(input); + KNumber arg1 = _last_number; + CosGrad(input); + KNumber arg2 = _last_number; + _last_number = arg1 / arg2; +} + +void CalcEngine::TangensHyp(KNumber input) +{ + if (input.type() == KNumber::SpecialType) { + if (input == KNumber("nan")) _last_number = KNumber("nan"); + if (input == KNumber("inf")) _last_number = KNumber::One; + if (input == KNumber("-inf")) _last_number = KNumber::MinusOne; + return; + } + + CALCAMNT tmp_num = static_cast<double>(input); + _last_number = KNumber(double(TANH(tmp_num))); +} + +KNumber CalcEngine::evalOperation(KNumber arg1, Operation operation, + KNumber arg2) +{ + if (!_percent_mode || Operator[operation].prcnt_ptr == NULL) + { + return (Operator[operation].arith_ptr)(arg1, arg2); + } else { + _percent_mode = false; + return (Operator[operation].prcnt_ptr)(arg1, arg2); + } +} + +void CalcEngine::enterOperation(KNumber number, Operation func) +{ + _node tmp_node; + + if (func == FUNC_BRACKET) + { + tmp_node.number = 0; + 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; + + _stack.push(tmp_node); + + evalStack(); +} + +bool CalcEngine::evalStack(void) +{ + // this should never happen + if (_stack.isEmpty()) KMessageBox::error(0L, i18n("Stack processing error - empty stack")); + + _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; + 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() +{ + _error = false; + _last_number = KNumber::Zero; + + _stack.clear(); +} + + |