算术表达式的计算在我们日常的运用中是十分广泛的,特别是对于基本的四则混合运算的表达式。在我们习惯的计算表达方式中,一般来说是
中缀表达式类型的。
中缀表达式的计算比较复杂,它必须遵守以下三条规则:
(1) 先计算括号内,后计算括号外;
(2) 在无括号或同层括号内,先进行乘除运算,后进行加减运算,即乘除运算的优先级高于加减运算的优先级;
(3) 同一优先级运算,从左向右依次进行。
中缀表达式符合我们一般的习惯,但是在计算机的计算中,它实现的时候比较复杂,要考虑的因素比较多。为了方便进行计算,我们可以采用后缀表达式来进行计算,因为这个类型的表达式更符合计算机的口味吧(这个是 波兰科学家卢卡谢维奇提出的,扯远了:-))
//计算公式 中缀表达式转后缀表达式算法
计算后缀表达式的算法
主函数代码
程序写得有点乱,经过我简单的测试,目前还没有发现什么问题,如果大家有什么好的建议都可以告诉我o(∩_∩)o...哈哈,还有个问题,就是我把分母是0的时候整个表达式返回值改成了-1.0。
对应精度的问题会引发比较严重的错误,比如说(0.9-0.8-0.1)*100000000000结果不是我们想希望的。
参考文章
http://www.cnblogs.com/ZHOULONG/archive/2008/04/04/1137833.html
http://www.cnblogs.com/flyingbread/archive/2007/02/03/638932.html
中缀表达式的计算比较复杂,它必须遵守以下三条规则:
(1) 先计算括号内,后计算括号外;
(2) 在无括号或同层括号内,先进行乘除运算,后进行加减运算,即乘除运算的优先级高于加减运算的优先级;
(3) 同一优先级运算,从左向右依次进行。
中缀表达式符合我们一般的习惯,但是在计算机的计算中,它实现的时候比较复杂,要考虑的因素比较多。为了方便进行计算,我们可以采用后缀表达式来进行计算,因为这个类型的表达式更符合计算机的口味吧(这个是 波兰科学家卢卡谢维奇提出的,扯远了:-))
//计算公式 中缀表达式转后缀表达式算法
- int Offpos(char *str)
- {
- if (!str)
- return -1 ;
- int pos = 0 ;
- while (*str) {
- if ( ('+' == *str) ||
- ('-' == *str) ||
- ('*' == *str) ||
- ('/' == *str) ||
- ('@' == *str) ||
- (')' == *str) ||
- ('!' == *str))
- break ;
- if (((*str >= '0') && (*str <= '9'))
- || ('.' == *str)) {
- pos++ ;
- str++ ;
- }
- else {
- return -1 ;
- }
- }
- return pos ;
- }
- //转化为后缀算术表达式
- char *Prase(char *datas, char *str)
- {
- if (!str || '@' != *str)
- return NULL ;
- //假设用来处理符合的堆栈
- char symbol[1024] = { 0 } ;
- char *value = NULL ;
- char *sign = NULL ;
- value = datas ;
- sign = symbol ;
- int pos = 0 ;
- char c ;
- *sign++ = *str ;
- *value++ = *str ;
- //处理一些负数的情况
- if (('@' == *str) && ('-' == *(str+1))) {
- *value++ = '0' ;
- *value++ = '!' ;
- }
- str++ ;
- c = *str ;
- while (*str) {
- switch (*str) {
- //@字符串结束,弹出所有的操作符
- case '@' :
- c = *(sign - 1) ;
- if (c != '@') {
- sign-- ;
- while (*sign != '@') {
- *value++ = *sign-- ;
- *value++ = '!' ;
- }
- }
- break ;
- //'('符合进入堆栈
- case '(' :
- *sign++ = '(' ;
- break ;
- //弹出到'('为止的所有符号堆栈里面的字符
- case ')' :
- //to do ;
- sign-- ;
- while ('(' != *sign) {
- if ('@' == *sign)
- return NULL ;
- *value++ = *sign ;
- *value++ = '!' ;
- sign-- ;
- }
- *sign = 0 ;
- break ;
- case '-' :
- c = *(str-1) ;
- //如果 '-' 的意义表示负号
- if ( c == '-' ||
- c == '(' ||
- c == '+' ||
- c == '*' ||
- c == '/') {
- *value++ = '-' ;
- break ;
- }
- //如果 '-' 的意义表示负号
- if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
- *sign++ = *str ;
- break ;
- }
- //弹出所有的堆栈符号
- sign-- ;
- while (!(('@' == *sign) || ('(' == *sign))) {
- c = *sign ;
- *value++ = c ;
- *value++ = '!' ;
- sign-- ;
- }
- sign++ ;
- *sign++ = *str ;
- break ;
- case '+' :
- //+符号不做那么严格的处理了
- c = *str ;
- if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
- *sign++ = c ;
- break ;
- }
- sign-- ;
- while (!(('@' == *sign) || ('(' == *sign))) {
- c = *sign ;
- *value++ = c ;
- *value++ = '!' ;
- sign-- ;
- }
- sign++ ;
- *sign++ = *str ;
- break ;
- case '*' :
- case '/' :
- //这两个的符号优先级别比+-高
- c = *str ;
- if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
- *sign++ = c ;
- break ;
- }
- c = *(sign - 1) ;
- if (('+' == c) || ('-' == c)) {
- *sign++ = *str ;
- }
- if (('*' == c) || ('/' == c)) {
- *value++ = c ;
- *value++ = '!' ;
- sign-- ;
- *sign++ = *str ;
- }
- break ;
- default :
- //默认数据值压入堆栈
- if ((*str >= '0') && (*str <= '9')) {
- pos = Offpos(str) ;
- strncpy(value, str, pos) ;
- str += pos ;
- value += pos ;
- *value++ = '!' ;
- }
- str-- ;
- break ;
- }
- str++ ;
- }
- return datas ;
- }
计算后缀表达式的算法
- //计算公式
- float Calculate(char *str)
- {
- if (!str)
- return -1.0 ;
- if ('@' != *str)
- return -1.0 ;
- str++ ;
- float datas[1024] = { 0.0 } ;
- float f = 0.0 ;
- float *temp = datas ;
- int pos = 0 ;
- while (*str) {
- switch (*str) {
- case '@' :
- break ;
- case '+' :
- f = *(--temp) ;
- temp-- ;
- *temp += f ;
- temp++ ;
- *temp = 0.0 ;
- str++ ;
- break ;
- case '-' :
- //处理负号的问题
- if ((*(str+1) >= '0') && (*(str+1) <= '9')) {
- f = atof(str) ;
- str++ ;
- pos = Offpos(str) ;
- //pos++ ;
- str += pos ;
- // str-- ;
- *temp++ = f ;
- }
- else {
- f = *(--temp) ;
- temp-- ;
- *temp -= f ;
- temp++ ;
- *temp = 0.0 ;
- str++ ;
- }
- break ;
- case '*' :
- f = *(--temp) ;
- temp-- ;
- *temp *= f ;
- temp++ ;
- *temp = 0.0 ;
- str++ ;
- break ;
- case '/' :
- f = *(--temp) ;
- temp-- ;
- //如果分母是0
- if ((f > -(1e-6)) && (f < 1e-6))
- return -1 ;
- *temp /= f ;
- temp++ ;
- *temp = 0.0 ;
- str++ ;
- break ;
- default :
- if ((*str >= '0') && (*str <= '9')) {
- f = atof(str) ;
- pos = Offpos(str) ;
- str += pos ;
- *temp++ = f ;
- // str-- ;
- }
- break ;
- }
- str++ ;
- }
- return *(--temp) ;
- }
- int main(int argc, char* argv[])
- {
- char datas[1024] = { 0 } ;
- char temp[] = "@-(20+-23*4)/(-1-20/2)@" ;
- float f = 0.0 ;
- Prase(datas, temp) ;
- f = Calculate(datas) ;
- return 0;
- }
对应精度的问题会引发比较严重的错误,比如说(0.9-0.8-0.1)*100000000000结果不是我们想希望的。
参考文章
http://www.cnblogs.com/ZHOULONG/archive/2008/04/04/1137833.html
http://www.cnblogs.com/flyingbread/archive/2007/02/03/638932.html