-
-
[原创]四则混合运算的计算
-
发表于: 2009-9-22 16:02 5531
-
大家好啊,好久没来看雪了,嘿嘿。关于四则运算,网上有很多源代码,而这一个是我自己写出来的,分享给大家吧:
1、支持加减乘除
2、支持括号运算,当然是(),其他乱成八糟的括号不认识
3、能识别括号匹配
4、支持负数,浮点数,整数运算
主要思路是:
A、将中缀表达式转化为后缀表达式
B、用后缀表达式进行四则运算
嘿嘿,还记得以前用VBS调用ScriptControl控件计算简单四则混合运算被大家取笑的事……
呵呵,现在都是面向对象,用一个CExp类完成主要的功能:
////m_calc是CExp类的成员,负责计算
CString s;
GetDlgItemText(IDC_EDIT1, s);
m_calc.SetMidExp(s.GetBuffer(0));
if (m_calc.Mid2BackExp()){
SetDlgItemText(IDC_EDIT2, m_calc.GetResult());
double d = m_calc.calcResult();
s.Format("%.3f", d);
SetDlgItemText(IDC_EDIT3, s);
}
else{
AfxMessageBox("你输入的表达式有问题!");
}
当然,这代码还存在着很多不足,比如,除数为零判断,比如其他函数计算如SIN,COS等,嘿嘿,不过如果大家能修定得更加完善,那本人的目的也达到了,利人利已!希望大家多多指教!
对于Mid2BackExp()函数作一下修改:
测试中发现 3+2-5*0-2 算出结果为7,与实际不符合,仔细分析后发现,如果是加减法,除非遇到(,或者栈为空,可以入栈,其它的运算符必须全部出来!
整个函数如下:
BOOL CExp::Mid2BackExp()//中缀表达式转后缀式
{
// 1、如果是数字则直接放入后缀表达式数组;
// 2、如果是左括号则直接入栈;
// 3、如果是右括号,则把从栈顶直到对应左括号之间的运算符依次退栈,并清除对应的左括号;
// 4、对于运算符,如果该运算符的优先级大于栈顶优先级,则直接入栈,若该运算符的优先级小于等于栈顶优先级,则先把栈顶运算符出栈,写入后缀表达式数组,然后再入栈;
// 5、扫描完成后,取出栈中所有运算符,写入后缀表达式数组。
int nLastIndex;
int nLen = m_midExp.GetLength();
if (0 >= nLen) return FALSE; //啥也没有转个屁啊!
m_bkExp.Empty(); //首先将后缀表达式数组清空
if (! IsBracketMatched()){ //括号不匹配也不转!
return FALSE;
}
for(int i=0; i<nLen; i++){
char c = m_midExp.GetAt(i);
if (c >= '0' && c <= '9' || '.' == c || '-' == c){ //如果是数字,直接放入后缀表达式数组,小数点也算进来
if (c == '-'){ //负数的情况
if (m_stkOper.empty()){ //不含括号的情况
if (m_bkExp.IsEmpty()){ //如果后缀数组也为空,那肯定是负数了!,对应 "-xx" 的情况
m_bkExp += c;
continue;
}
}
else{
if ('(' == m_stkOper.top()){ //对于含括号的情况,第一个是负数
//如果后缀数组最后一位不是数字,那肯定是负数 ,对应 "(-(" 的情况
nLastIndex = m_bkExp.GetLength()-1;
if (nLastIndex>= 0){
if (! isdigit(m_bkExp.GetAt(nLastIndex))){
m_bkExp += c;
continue;
}
}
else{ //后缀数组里没内容,对应 "(-xx" 的情况
m_bkExp += c;
continue;
}
}
}
}
else{ //其他情况
m_bkExp += c;
continue;
}
}
nLastIndex = m_bkExp.GetLength();
if (nLastIndex != 0) {
nLastIndex--;
if (',' != m_bkExp.GetAt(nLastIndex)) m_bkExp += ',';
}
//如果是运算符的话...
switch(c){
case '+':
case '-':
if (!m_stkOper.empty()) //+-法的优先级小于等于同级算法和乘除法 直接弹出所有非括号的运算符!
{
while(!m_stkOper.empty()){
if('(' != m_stkOper.top()){
m_bkExp += m_stkOper.top();
m_bkExp += ',';
m_stkOper.pop();
}
else{ //遇到了括号,就结束
break;
}
}
m_stkOper.push(c);
}
else{ //如果栈中无元素,直接入栈
m_stkOper.push(c);
}
break;
case '*':
case '/':
//如果比栈顶元素优先级大,则入栈,否则同上
if ( !m_stkOper.empty()){
switch(m_stkOper.top()){
case '+':
case '-':
case '(': //加减法不能欺负,括号又欺负不了,直接入栈吧!
m_stkOper.push(c);
break;
case '*':
case '/': //同级的就弹出去!
m_bkExp += m_stkOper.top();
m_bkExp += ',';
m_stkOper.pop();
m_stkOper.push(c);
}
}
else{//如果栈中无元素,直接入栈
m_stkOper.push(c);
}
break;
case '(': //左括号直接入栈
m_stkOper.push(c);
break;
case ')':
while(m_stkOper.top()!='('){//弹出两括号之间的所有符号
m_bkExp += m_stkOper.top();
m_bkExp += ',';
m_stkOper.pop();
}
m_stkOper.pop(); //弹出左括号
}
}
while(!m_stkOper.empty()){
nLastIndex = m_bkExp.GetLength()-1;
if (',' != m_bkExp.GetAt(nLastIndex)) m_bkExp += ',';
m_bkExp += m_stkOper.top();
m_stkOper.pop();
m_bkExp += ',';
}
return TRUE;
}
将混合运算已经封装成dll文件,函数原型
double __stdcall ExpressStrCalc (LPCTSTR sExp);
在VB/VC下调用测试成功!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创]九重妖塔设计思路 9243
- [原创]Hello-CTF破解_不问年少 2285
- [原创]剧情式CM——九重妖塔前传III 4278
- [原创]剧情式CM——九重妖塔前传II 3694
- [原创]剧情式CM——九重妖塔前传!!! 5294