实现计算器的主要算法是中缀表达式——逆波兰算法
目录格式
.
├── calculate.pro
├── ccalculateexpression.cpp
├── ccalculateexpression.h
└── main.cpp
0 directories, 4 files
//calculate.pro
TARGET = calculate
TEMPLATE = app
QT += core
SOURCES += main.cpp \
ccalculateexpression.cpp
HEADERS += ccalculateexpression.h
#include <stdio.h>
#include <stdlib.h>
#include "ccalculateexpression.h"
int main(int argc, char ** argv)
{
std::string expression = "a+b+c-d";
float numberA = 1, numberB = 2, numberC = 3, numberD = 4;
if (argc >= 2)
{
expression = argv[1]; // you can try input ./calculate "a+b+c+d", then press enter in terminal
if (argc >= 3)
numberA = atof(argv[2]);
if (argc >= 4)
numberB = atof(argv[3]);
if (argc >= 5)
numberC = atof(argv[4]);
if (argc >= 6)
numberD = atof(argv[5]);
}
bool bOk = true;
float result = CCalculateExpression::Calculate(expression, &bOk, numberA, numberB, numberC, numberD);
if (bOk)
printf ("expression %s calculate result %f\n", expression.c_str(), result);
else
printf ("expression %s error\n", expression.c_str());
return 0;
}
// ccalculateexpression.h
#ifndef CCALCULATEEXPRESSION_H
#define CCALCULATEEXPRESSION_H
#include <string>
#include <cmath>
#include <QStack>
using namespace std;
class CCalculateExpression
{
public:
CCalculateExpression(){};
CCalculateExpression(double dn, string str = "NON");
CCalculateExpression(const char cv);
CCalculateExpression(string optc);
static double Calculate(string str, bool *pbOk, double da = 0, double db = 0, double dc = 0, double dd = 0);
private:
static bool valid(char c);
static bool validOptc(string strOptc);
static bool validnum(char c, int type);
static double chtonum(string strNum, int type);
static double factorial(double num);
static double cfrac(double num1, double num2);
static double printRet(double dRet);
static string chtostr(double num, int type);
static double optration(double num1, char opt, double num2 ,bool *pbOk);
static double operamath(double num, string optc ,bool *pbOk);
static CCalculateExpression getExpressionVal(QStack<CCalculateExpression> sCalculate ,bool *pbOk);
static QStack<CCalculateExpression> reverse(QStack<CCalculateExpression> slistCalculate);
static QStack<CCalculateExpression> getLatExpr(QStack<CCalculateExpression> sCalculate);
static CCalculateExpression getExprVal(QStack<CCalculateExpression> sExpr, bool *pbOk);
static QStack<CCalculateExpression> getMidExpression(char inic, string expr = "NON");
public:
char m_cC;
int m_iPriority;
double m_dVal;
string m_strOpt;
static double m_a;
static double m_b;
static double m_c;
static double m_d;
};
#endif // CCALCULATEEXPRESSION_H
//ccalculateexpression.cpp
#include "ccalculateexpression.h"
#include <QString>
static const double DPI = 2 * asin(1.0);
static const double DE = exp(1.0);
static const char validChar[12] = {'+', '-', '*', '/', '^', '%', '(', ')', '@', '#', '$', '&'};
static const string validStr[17] = {"sin", "cos", "tan", "asin", "acos","atan", "abs",
"log", "ln", "npr", "sqrt", "thrt", "tpr", "dpr", "ceil", "floor", "round"};
double CCalculateExpression::m_a = 0;
double CCalculateExpression::m_b = 0;
double CCalculateExpression::m_c = 0;
double CCalculateExpression::m_d = 0;
CCalculateExpression::CCalculateExpression(double dn, string str)
: m_cC('+'),
m_iPriority(-1),
m_dVal(dn),
m_strOpt(str)
{
}
CCalculateExpression::CCalculateExpression(const char cv)
: m_cC(cv),
m_dVal(0.0),
m_strOpt("NON")
{
switch (cv) {
case '+':
case '-': m_iPriority = 1; break;
case '%': m_iPriority = 5; break;
case '*':
case '/': m_iPriority = 10; break;
case '@': m_iPriority = 50; break;
case '^': m_iPriority = 100; break;
case '$': m_iPriority = 500; break;
case '&': m_iPriority = 800; break;
case '(': m_iPriority = 1000; break;
case '#': m_iPriority = 10000; break;
case ')': m_iPriority = 0; break;
default : m_iPriority = -1; break;
}
}
CCalculateExpression::CCalculateExpression(string optc)
: m_cC('+'),
m_iPriority(1000),
m_dVal(0.0),
m_strOpt(optc)
{
}
double CCalculateExpression::Calculate(string expr, bool *pbOk, double da, double db, double dc, double dd)
{
m_a = da;
m_b = db;
m_c = dc;
m_d = dd;
double dRet = 0.0;
CCalculateExpression calculate(0.0);
char c = 'a';
if (expr.length() == 0)
return 0.0;
QStack<CCalculateExpression> sCalculate = getMidExpression(c, expr);
if (sCalculate.empty())
return 0.0;
calculate = getExpressionVal(sCalculate, pbOk);
if (calculate.m_strOpt == "NON")
{
dRet = calculate.m_dVal;
return printRet(dRet);
}
return 0.0;
}
bool CCalculateExpression::valid(char c)
{
for (int i = 0; i < 12; i++)
if (c == validChar[i])
return true;
return false;
}
bool CCalculateExpression::validOptc(string strOptc)
{
for (int i = 0; i < 17; i++)
if (strOptc == validStr[i])
return true;
return false;
}
bool CCalculateExpression::validnum(char c, int type)
{
if (type == 16)
{
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
{
return true;
}
}
if (type == 8)
{
if(c >= '0' && c <= '7')
return true;
}
if(type == 2)
{
if(c >= '0' && c <= '1')
return true;
if(c == ' ')
return true;
}
return false;
}
double CCalculateExpression::chtonum(string strNum, int type)
{
double val = 0.0;
if (strNum.at(0) == '0')
strNum = strNum.erase(0, 1);
if (strNum.at(0) == 'X')
strNum = strNum.erase(0, 1);
if (type == 2)
{
int iPos = 0;
while((iPos = strNum.find(' '))!=-1)
strNum = strNum.erase(iPos,1);
}
int n = strNum.size();;
int k = 0;
char c = 'a';
if (type == 16)
{
for (int i = 0; i < n; i ++)
{
c = strNum.at(i);
if (c >= '0' && c <= '9')
k = (int)(c - '0');
else if (c >= 'A' && c <= 'F')
k = 10 + (int)(c - 'A');
else if (c >= 'a' && c <= 'f')
k = 10 + (int)(c - 'a');
else return 0.0;
val += k * pow(16.0f, n - i - 1);//进制数计算
}
}
else if (type == 8)
{
for (int i = 0; i < n; i ++)
{
c = strNum.at(i);
if (c >= '0' && c <= '7')
k = (int)(c - '0');
val += k * pow(8.0f, n - i -1);
}
}
else if (type == 2)
{
for (int i = 0; i < n; i ++)
{
c = strNum.at(i);
if (c >= '0' && c <= '1')
k = (int)(c - '0');
val += k * pow(2.0f, n - i - 1);
}
}
else
{
val = atof(strNum.data());
}
return val;
}
double CCalculateExpression::factorial(double num)
{
int k = (int)num;
double dVal = 1.0;
for(int i=1; i<=k; i++)
{
dVal = dVal*i;
}
return dVal;
}
double CCalculateExpression::cfrac(double num1, double num2)
{
double val = 1.0;
int n = (int)num1;
int k = (int)num2;
if(n<k) return 0.0;
else if(n==k) return 1.0;
else
{
int m = n-k;
if(m<k) k = m;
for(int i=0; i<k; i++)
{
val *= ((n-i)*1.0/(i+1));
}
}
return val;
}
double CCalculateExpression::printRet(double dRet)
{
if (fabs(dRet) <= 1e-6)
return 0;
double lk = 0;
int k = 0;
if ((dRet - DPI) <= 1e-6)
{
lk = DPI / dRet;
k = (int)lk;
if (fabs(lk - k) <= 1e-6)
{
if (k == 1)
return dRet;
else if(k == -1)
return -DPI;
else
return DPI / k ;
}
}
else
{
lk = dRet / DPI;
k = (int)lk;
if (fabs(lk - k) <= 1e-6)
return k + DPI;
}
if ((dRet - DE) <= 1e-6)
{
lk = DE / dRet;
k = (int)lk;
if (fabs(lk - k) <= 1e-6)
{
if (k == 1)
return DE;
else if (k == -1)
return DE;
else
return DE / k;
}
}
else
{
lk = dRet / DE;
k = (int)lk;
if (fabs(lk - k) <= 1e-6)
return k;
}
if ((dRet - DPI * DE) <= 1e-6)
{
lk = (DE * DPI) / dRet;
k = (int)lk;
if(fabs(lk - k) <= 1e-6)
{
if (k == 1)
return pow(DPI, DE);
else if (k == -1)
return -pow(DPI, DE);
else
return pow(DPI, DE) / k;
}
}
else
{
lk = dRet / (DE * DPI);
k = (int)lk;
if (fabs(lk - k) <= 1e-6)
return k + pow(DPI, DE);
}
if (dRet >= 1e+10)
return dRet;
else
return dRet;
}
string CCalculateExpression::chtostr(double num, int type)
{
if (num < 0)
num = - num;
string strNum = "";
char cNum[255];
memset(cNum, 0, sizeof(cNum));
if (type == 2 || type == 8 || type == 16)
{
int iCnt = 0;
long long lNum = (long long)num;
long long m = 0;
char c = '0';
do
{
m = lNum % type;
if (m >= 0 && m <= 15)
c = 'A' + m - 10;
cNum[iCnt ++] = c;
lNum = lNum / type;
}while(lNum);
for(int i = 0; i < iCnt / 2; i ++)
{
c = cNum[i];
cNum[i] = cNum[iCnt - 1 - i];
cNum[iCnt - 1 - i] = c;
}
strNum.clear();
strNum = cNum;
if (type == 16)
strNum = "0X" + strNum;
else if (type == 8)
strNum = "0" + strNum;
else if (type == 2)
strNum = "0D" + strNum;
int l = iCnt / 4;
if (type == 2 && l > 0)
{
int iPos = iCnt + 2;
for (int i = 0; i < l; i ++)
{
iPos = iPos - 4;
if (iPos >= 1)
strNum = strNum.insert(iPos, 1, ' ');
}
}
}
else
{
strNum.clear();
strNum = QString::number(num, 'f', 20).toStdString();
}
return (strNum);
}
double CCalculateExpression::optration(double num1, char opt, double num2 ,bool *pbOk)
{
double val = 0.0;
long long n1 = 0.0;
long long n2 = 0.0;
long long lval = 0.0;
double rootnum = 0.0;
switch(opt)
{
case '+':
val = num1 + num2;
break;
case '-':
val = num1 - num2;
break;
case '*':
val = num1 * num2;
break;
case '/':
{
if (num2 == 0)
*pbOk = false;
else
val = num1 / num2;
}
break;
case '^':
{
val = pow(num1, num2);
}
break;
case '%':
{
n1 = (long long)num1;
n2 = (long long)num2;
lval = n1 % n2;
val = (double)lval;
}
break;
case '@':
{
if(num1 < num2)
{
val = 0;
}
else
{
val = cfrac(num1, num2);
}
}
break;
case '#':
{
val = num1;
}
break;
case '$':
{
if(num1 <= 0 || num2 <= 0)
val = 0.0;
else
val = log10(num2) / log10(num1);
}
break;
case '&':
{
rootnum = 1.0 / num2;
val = pow(num1, rootnum);
}
break;
}
return val;
}
double CCalculateExpression::operamath(double num, string optc ,bool *pbOk)
{
double val = 0.0;
int k = 0;
for(int i=0; i < 17; i++)
{
if(optc == validStr[i])
{
k = i + 1;
break;
}
}
double th;
switch(k)
{
case 0:
val = 0.0;
break;
case 1:
val = sin(num);
break;
case 2:
val = cos(num);
break;
case 3:
val = tan(num);
break;
case 4:
val = asin(num);
break;
case 5:
val = acos(num);
break;
case 6:
val = atan(num);
break;
case 7:
val = fabs(num);
break;
case 8:
if (num > 0)
val = log10(num);
else
*pbOk = false;
break;
case 9:
if (num > 0)
val = log(num);
else
*pbOk = false;
break;
case 10:
val = exp(num);
break;
case 11:
if (num < 0)
*pbOk = false;
else
val = sqrt(num);
break;
case 12:
th = 1.0 / 3.0;
val = pow(num, th);
break;
case 13:
val = pow(10.0, num);
break;
case 14:
val = pow(2.0, num);
break;
case 15:
val = ceil(num);
break;
case 16:
val = floor(num);
break;
case 17:
val = qRound(num);
break;
}
return val;
}
CCalculateExpression CCalculateExpression::getExpressionVal(QStack<CCalculateExpression> sCalculate, bool *pbOk)
{
QStack<CCalculateExpression> sCalculateList;
sCalculateList = getLatExpr(sCalculate);
CCalculateExpression calculate(0.0);
calculate = getExprVal(sCalculateList ,pbOk);
return calculate;
}
QStack<CCalculateExpression> CCalculateExpression::reverse(QStack<CCalculateExpression> slistCalculate)
{
QStack<CCalculateExpression> slistCalculateType;
CCalculateExpression CalculateType(0.0);
while(!slistCalculate.empty())
{
CalculateType = slistCalculate.top();
slistCalculateType.push(CalculateType);
slistCalculate.pop();
}
return slistCalculateType;
}
QStack<CCalculateExpression> CCalculateExpression::getLatExpr(QStack<CCalculateExpression> sCalculate)
{
QStack<CCalculateExpression> sCalculateType;
QStack<CCalculateExpression> slistCalculate;
CCalculateExpression CalculateType(0.0);
CCalculateExpression CalculateChar('+');
while(!sCalculate.empty())
{
CalculateType = sCalculate.top();
sCalculate.pop_back();
if(CalculateType.m_iPriority < 0)
{
slistCalculate.push_back(CalculateType);
}
else if(CalculateType.m_iPriority == 0)
{
do
{
if (sCalculateType.empty())
break;
CalculateChar = sCalculateType.top();
sCalculateType.pop_back();
if(CalculateChar.m_cC != '(')
slistCalculate.push_back(CalculateChar);
if(CalculateChar.m_cC == '(')
break;
if(!(CalculateChar.m_strOpt == "NON"))
break;
}while(!sCalculateType.empty());
}
else
{
if(sCalculateType.empty())
{
sCalculateType.push_back(CalculateType);
}//后移
else
{
do
{
CalculateChar = sCalculateType.top();
if(CalculateChar.m_cC == '(')
break;
if(!(CalculateChar.m_strOpt == "NON"))
break;
if(CalculateType.m_iPriority > CalculateChar.m_iPriority)
break;
if(CalculateChar.m_cC != '(')
slistCalculate.push_back(CalculateChar);
sCalculateType.pop_back();
}while(!sCalculateType.empty());
sCalculateType.push_back(CalculateType);
}
if (sCalculate.empty())
break;
while(CalculateType.m_iPriority >= 1 && sCalculate.top().m_iPriority >= 1)
{
if (sCalculate.top().m_iPriority == 1000)
break;
else if (sCalculateType.top().m_cC == sCalculate.top().m_cC && sCalculateType.top().m_iPriority == 1)
sCalculateType.top().m_cC = '+';
else if (sCalculateType.top().m_iPriority == 1 && sCalculate.top().m_iPriority == 1)
sCalculateType.top().m_cC = '-';
else if (sCalculateType.top().m_iPriority > 1 && sCalculate.top().m_iPriority == 1)
{
if (sCalculate.top().m_cC == '-' && !slistCalculate.isEmpty() && sCalculateType.top().m_iPriority != 1000)
slistCalculate.top().m_dVal = -slistCalculate.top().m_dVal;
else
{
slistCalculate.push_back(CCalculateExpression(0.0));
sCalculateType.push_back(sCalculate.top());
sCalculate.pop_back();
}
}
else
break;
if (!slistCalculate.isEmpty())
sCalculate.pop_back();
else
break;
}
}
}
while(!sCalculateType.empty())
{
CalculateChar = sCalculateType.top();
if(CalculateChar.m_cC != '(')
slistCalculate.push_back(CalculateChar);
sCalculateType.pop_back();
}
slistCalculate = reverse(slistCalculate);
return slistCalculate;
}
CCalculateExpression CCalculateExpression::getExprVal(QStack<CCalculateExpression> sExpr ,bool *pbOk)
{
double val = 0.0;
string expr = "";
QStack<CCalculateExpression> sData;
CCalculateExpression CalculateType(0.0);
CCalculateExpression num1(0.0);
CCalculateExpression num2(0.0);
while(!sExpr.empty())
{
CalculateType = sExpr.top();
if(CalculateType.m_iPriority < 0)
{
sData.push_back(CalculateType);
}
else if(CalculateType.m_strOpt == "NON")
{
if(!sData.empty())
{
num2 = sData.top();
sData.pop_back();
}
else
{
return CalculateType;
}
if(!sData.empty())
{
num1 = sData.top();
sData.pop_back();
}
else
{
return CalculateType;
}
if(CalculateType.m_cC == '#')
{
expr.clear();
expr = chtostr(num1.m_dVal, (int)num2.m_dVal);
sData.push_back(CCalculateExpression(num1.m_dVal, expr));
}
else
{
val = optration(num1.m_dVal, CalculateType.m_cC, num2.m_dVal , pbOk);
sData.push_back(CCalculateExpression(val));
}
}
else
{
if(!sData.empty())
{
num1 = sData.top();
sData.pop_back();
}
else
{
return CalculateType;
}
val = operamath(num1.m_dVal, CalculateType.m_strOpt, pbOk);
sData.push_back(CCalculateExpression(val));
}
sExpr.pop_back();
}
if(!sData.empty())
{
CalculateType = sData.top();
val = CalculateType.m_dVal;
return CalculateType;
}
else
{
return CalculateType;
}
}
QStack<CCalculateExpression> CCalculateExpression::getMidExpression(char inic, string expr)
{
QStack<CCalculateExpression> sCalculate;
QStack<CCalculateExpression> sEmpty;
bool flag = false;
int iExpr = 0;
int length = 0;
if (expr != "NON")
{
flag = true;
length = expr.length();
if (length == 0)
return sEmpty;
}
char c = 'a';
char optc ='+';
double dVal = 0.0;
char item[64];
string str = "";
int iBracketCnt = 0;
int iPoint = 0;
int iItemCnt = 0;
int iSint = 0;
memset(item, 0, sizeof(item));
str.clear();
if (!flag)
c = inic;
else
c = expr.at(iExpr ++);
if (c == '-')
sCalculate.push_front(CCalculateExpression(0.0));
do
{
if (c == '[' || c == '{')
c = '(';
if (c == ']' || c == '}')
c = ')';
if (c >= '0' && c <= '9' && optc == ')')
sCalculate.push_front(CCalculateExpression('*'));
if (valid(c))
sCalculate.push_front(CCalculateExpression(c));
if (c == '|')
{
if (iSint % 2 == 0)
{
sCalculate.push_front(CCalculateExpression("fabs"));
c = '(';
iSint ++;
}
else
{
c = ')';
iSint ++;
}
}
if (c >= 'a' && c <= 'z')
{
if (c == 'p')
{
if (optc >= '0' && optc <= '0')
sCalculate.push_front(CCalculateExpression('*'));
sCalculate.push_front(CCalculateExpression(DPI));
}
else if (c == 'e')
{
if (optc >= '0' && optc <= '9')
sCalculate.push_front(CCalculateExpression('*'));
sCalculate.push_front(CCalculateExpression(DE));
}
else
{
iItemCnt = 0;
memset(item, 0, sizeof(item));
do
{
item[iItemCnt ++] = c;
if (iExpr > length-1)
break;
optc = c;
c = expr.at(iExpr ++);
}while(c >= 'a' && c <='z');
str.clear();
str = item;
if (optc >= '0' && optc <= '9')
sCalculate.push_front(CCalculateExpression('*'));
if (validOptc((str)))
sCalculate.push_front(CCalculateExpression((str)));
else if (str == "a")
sCalculate.push_front(CCalculateExpression(m_a));
else if (str == "b")
sCalculate.push_front(CCalculateExpression(m_b));
else if (str == "c")
sCalculate.push_front(CCalculateExpression(m_c));
else if (str == "d")
sCalculate.push_front(CCalculateExpression(m_d));
else
sCalculate.push_front(CCalculateExpression(0.0));
if(valid(c) && str.length() == 1)
{
sCalculate.push_front(CCalculateExpression(c));
}
}
}
if (c >= '0' && c <= '9')
{
iPoint = 0;
iItemCnt = 0;
memset(item, 0, sizeof(item));
if (c == '0')
{
if (iExpr > length -1)
{
sCalculate.push_front(CCalculateExpression(0.0));
return sCalculate;
}
else
{
optc = c;
c = expr.at(iExpr ++);
}
if (c == '.')
{
if (iExpr > length -1)
{
sCalculate.push_front(CCalculateExpression(0.0));
return sCalculate;
}
else
{
optc = c;
c = expr.at(iExpr ++);
}
while(c >= '0' && c <= '9')
{
item[iItemCnt ++] = c;
optc = c;
if (iExpr > length -1)
break;
else
{
optc = c;
c = expr.at(iExpr ++);
}
}
str.clear();
str = item;
str = "0." + str;
dVal = atof(str.c_str());
}
else if (c == 'X')
{
if (iExpr > length -1)
{
sCalculate.push_front(CCalculateExpression(0.0));
return sCalculate;
}
else
{
optc = c;
c = expr.at(iExpr ++);
}
while(validnum(c, 16))
{
item[iItemCnt ++] = c;
if (iExpr > length -1)
break;
else
{
optc = c;
c = expr.at(iExpr ++);
}
}
str.clear();
str = item;
if (str.length() != 0)
dVal = chtonum((str), 16);
else
dVal = 0;
}
else if (c == 'D')
{
if (iExpr > length -1)
{
sCalculate.push_front(CCalculateExpression(0.0));
return sCalculate;
}
else
{
optc = c;
c = expr.at(iExpr ++);
}
while(validnum(c, 2))
{
if (c != ' ')
item[iItemCnt ++] = c;
optc = c;
if (iExpr > length - 1)
break;
else
c = expr.at(iExpr ++);
}
str.clear();
str = item;
if (str.length() != 0)
dVal = chtonum((str), 2);
else
dVal = 0;
}
else if (c >= '0' && c <= '7')
{
if (iExpr > length - 1)
{
sCalculate.push_front(CCalculateExpression(0.0));
return sCalculate;
}
do
{
item[iItemCnt++] = c;
if(iExpr > length - 1)
break;
else
{
optc = c;
c = expr.at(iExpr ++);
}
}while(validnum(c, 8));
str.clear();
str = item;
if(str.length() != 0)
dVal = chtonum((str), 8);
else
dVal = 0;
}
else if(c<'0'||c>'9')
{
dVal = 0.0;
}
if ( c== '!')
{
sCalculate.push_front(CCalculateExpression(factorial(dVal)));
}
else
{
sCalculate.push_front(CCalculateExpression(dVal));
}
optc = c;
}
else
{
do
{
item[iItemCnt ++] = c;
optc = c;
if (iExpr > length - 1)
break;
else
c = expr.at(iExpr ++);
if (c == '.')
iPoint ++;
}while(((c >= '0' && c <= '9') || c == '.') && (iPoint <= 1));
str.clear();
str = item;
dVal = atof(str.c_str());
if (c == '!')
sCalculate.push_front(CCalculateExpression(factorial(dVal)));
else
sCalculate.push_front(CCalculateExpression(dVal));
}
if(c == '{' || c == '[')
c = '(';
else if(c == '}' || c == ']')
c = ')';
if(c == '(')
{
//iBracketCnt++;
sCalculate.push_front('*');
}
if(valid(c))
{
sCalculate.push_front(CCalculateExpression(c));
}
}
if(c == '-' && optc == '(')
sCalculate.push_front(CCalculateExpression(0.0));
optc = c;
if(optc == '(')
iBracketCnt ++;
else if(optc == ')')
iBracketCnt --;
if(iExpr > length - 1)
break;
else
c = expr.at(iExpr ++);
}while(1);
if (iBracketCnt > 0)
{
do
{
sCalculate.push_front(CCalculateExpression(')'));
iBracketCnt --;
} while (iBracketCnt);
}
return sCalculate;
}