mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 18:32:53 +00:00
886 lines
23 KiB
C++
886 lines
23 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "kcalc_core.h"
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
|
|
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, 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, ExecBinom, NULL}, // FUNC_BINOM
|
|
{ 7, ExecPower, NULL}, // FUNC_POWER
|
|
{ 7, ExecPwrRoot, NULL} // FUNC_PWR_ROOT
|
|
};
|
|
|
|
}
|
|
|
|
|
|
CalcEngine::CalcEngine() : percent_mode_(false) {
|
|
|
|
last_number_ = KNumber::Zero;
|
|
error_ = false;
|
|
}
|
|
|
|
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 kDebug() << "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 kDebug() << "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 kDebug() << "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 kDebug() << "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 == NULL) {
|
|
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;
|
|
|
|
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()
|
|
{
|
|
error_ = false;
|
|
last_number_ = KNumber::Zero;
|
|
|
|
stack_.clear();
|
|
}
|
|
|
|
|