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