You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeutils/kcalc/kcalc_core.cpp

1005 lines
23 KiB

/*
kCalculator, a scientific calculator for the X window system using the
TQt 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();
}