C语言 算术表达式

     算术表达式的计算在我们日常的运用中是十分广泛的,特别是对于基本的四则混合运算的表达式。在我们习惯的计算表达方式中,一般来说是 中缀表达式类型的。
     中缀表达式的计算比较复杂,它必须遵守以下三条规则:
     (1) 先计算括号内,后计算括号外;
     (2) 在无括号或同层括号内,先进行乘除运算,后进行加减运算,即乘除运算的优先级高于加减运算的优先级;
     (3) 同一优先级运算,从左向右依次进行。
    
    
中缀表达式符合我们一般的习惯,但是在计算机的计算中,它实现的时候比较复杂,要考虑的因素比较多。为了方便进行计算,我们可以采用后缀表达式来进行计算,因为这个类型的表达式更符合计算机的口味吧(这个是 波兰科学家卢卡谢维奇提出的,扯远了:-)
     //计算公式 中缀表达式转后缀表达式算法
  1. int Offpos(char *str)
  2. {
  3.         if (!str)
  4.                 return -1 ;

  5.         int pos = 0 ;

  6.         while (*str) {

  7.                 if (    ('+' == *str) ||
  8.                         ('-' == *str) ||
  9.                         ('*' == *str) ||
  10.                         ('/' == *str) ||
  11.                         ('@' == *str) ||
  12.                         (')' == *str) ||
  13.                         ('!' == *str))
  14.                         break ;


  15.                 if (((*str >= '0') && (*str <= '9'))
  16.                         || ('.' == *str)) {
  17.                         pos++ ;
  18.                         str++ ;
  19.                 }
  20.                 else {
  21.                         return -1 ;
  22.                 }


  23.         }

  24.         return pos ;
  25. }


  26. //转化为后缀算术表达式
  27. char *Prase(char *datas, char *str)
  28. {
  29.         if (!str || '@' != *str)
  30.                 return NULL ;


  31.         //假设用来处理符合的堆栈
  32.         char symbol[1024] = { 0 } ;

  33.         char *value = NULL ;
  34.         char *sign = NULL ;
  35.         value = datas ;
  36.         sign = symbol ;


  37.         int pos = 0 ;
  38.         char c ;

  39.         *sign++ = *str ;
  40.         *value++ = *str ;

  41.         //处理一些负数的情况
  42.         if (('@' == *str) && ('-' == *(str+1))) {
  43.                 *value++ = '0' ;
  44.                 *value++ = '!' ;
  45.         }
  46.         str++ ;
  47.         c = *str ;

  48.         while (*str) {

  49.                 switch (*str) {

  50.                         //@字符串结束,弹出所有的操作符
  51.                         case '@' :
  52.                                 c =  *(sign - 1) ;
  53.                                 if (c != '@') {
  54.                                         sign-- ;
  55.                                         while (*sign != '@') {
  56.                                                 *value++ = *sign-- ;
  57.                                                 *value++ = '!' ;
  58.                                         }
  59.                                 }
  60.                                 break ;

  61.                         //'('符合进入堆栈
  62.                         case '(' :

  63.                                 *sign++ = '(' ;
  64.                                 break ;

  65.                         //弹出到'('为止的所有符号堆栈里面的字符
  66.                         case ')' :
  67.                                 //to do ;
  68.                                 sign-- ;
  69.                                 while ('(' != *sign) {
  70.                                         if ('@' == *sign)
  71.                                                 return NULL ;
  72.                                         *value++ = *sign ;
  73.                                         *value++ = '!' ;
  74.                                         sign-- ;
  75.                                 }
  76.                                 *sign = 0 ;
  77.                                 break ;

  78.                         case '-' :

  79.                                 c = *(str-1) ;
  80.                                 //如果  '-' 的意义表示负号
  81.                                 if (    c == '-' ||
  82.                                         c == '(' ||
  83.                                         c == '+' ||
  84.                                         c == '*' ||
  85.                                         c == '/') {

  86.                                         *value++ = '-' ;
  87.                                         break ;
  88.                                 }

  89.                                 //如果  '-' 的意义表示负号
  90.                                 if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
  91.                                         *sign++ = *str ;
  92.                                         break ;
  93.                                 }

  94.                                 //弹出所有的堆栈符号
  95.                                 sign-- ;
  96.                                 while (!(('@' == *sign) || ('(' == *sign))) {
  97.                                         c = *sign ;
  98.                                         *value++ = c ;
  99.                                         *value++ = '!' ;
  100.                                         sign-- ;
  101.                                 }

  102.                                 sign++ ;
  103.                                 *sign++ = *str ;


  104.                                 break ;

  105.                         case '+' :
  106.                                 //+符号不做那么严格的处理了
  107.                                 c = *str ;
  108.                                 if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
  109.                                         *sign++ = c ;
  110.                                         break ;
  111.                                 }


  112.                                 sign-- ;
  113.                                 while (!(('@' == *sign) || ('(' == *sign))) {

  114.                                         c = *sign ;
  115.                                         *value++ = c ;
  116.                                         *value++ = '!' ;
  117.                                         sign-- ;
  118.                                 }

  119.                                 sign++ ;
  120.                                 *sign++ = *str ;

  121.                                 break ;

  122.                         case '*' :
  123.                         case '/' :
  124.                                 //这两个的符号优先级别比+-高
  125.                                 c = *str ;
  126.                                 if ((*(sign - 1) == '@') || (*(sign - 1) == '(')) {
  127.                                         *sign++ = c ;
  128.                                         break ;
  129.                                 }

  130.                                 c = *(sign - 1) ;

  131.                                 if (('+' == c) || ('-' == c)) {
  132.                                         *sign++ = *str ;
  133.                                 }
  134.                                 if (('*' == c) || ('/' == c)) {
  135.                                         *value++ = c ;
  136.                                         *value++ = '!' ;

  137.                                         sign-- ;
  138.                                         *sign++ = *str ;
  139.                                 }
  140.                                 break ;

  141.                         default :

  142.                                 //默认数据值压入堆栈
  143.                                 if ((*str >= '0') && (*str <= '9')) {
  144.                                         pos = Offpos(str) ;
  145.                                         strncpy(value, str, pos) ;
  146.                                         str += pos ;
  147.                                         value += pos ;
  148.                                         *value++ = '!' ;
  149.                                 }
  150.                                 str-- ;
  151.                                 break ;

  152.                 }
  153.                 str++ ;
  154.         }


  155.         return datas ;
  156. }

    计算后缀表达式的算法
  1. //计算公式
  2. float Calculate(char *str)
  3. {
  4.         if (!str)
  5.                 return -1.0 ;
  6.         if ('@' != *str)
  7.                 return -1.0 ;
  8.         str++ ;
  9.         float datas[1024] = { 0.0 } ;
  10.         float f = 0.0 ;
  11.         float *temp = datas ;
  12.         int pos = 0 ;
  13.         while (*str) {
  14.                 switch (*str) {
  15.                         case '@' :
  16.                                 break ;
  17.                         case '+' :
  18.                                 f = *(--temp) ;
  19.                                 temp-- ;
  20.                                 *temp += f ;
  21.                                 temp++ ;
  22.                                 *temp = 0.0 ;
  23.                                 str++ ;
  24.                                 break ;
  25.                         case '-' :
  26.                                 //处理负号的问题
  27.                                 if ((*(str+1) >= '0') && (*(str+1) <= '9')) {
  28.                                         f = atof(str) ;
  29.                                         str++ ;
  30.                                         pos = Offpos(str) ;
  31.                                         //pos++ ;
  32.                                         str += pos ;
  33. //                                        str-- ;
  34.                                         *temp++ = f ;
  35.                                 }
  36.                                 else {
  37.                                         f = *(--temp) ;
  38.                                         temp-- ;
  39.                                         *temp -= f ;
  40.                                         temp++ ;
  41.                                         *temp = 0.0 ;
  42.                                         str++ ;
  43.                                 }
  44.                                 break ;
  45.                         case '*' :
  46.                                 f = *(--temp) ;
  47.                                 temp-- ;
  48.                                 *temp *= f ;
  49.                                 temp++ ;
  50.                                 *temp = 0.0 ;
  51.                                 str++ ;
  52.                                 break ;
  53.                         case '/' :
  54.                                 f = *(--temp) ;
  55.                                 temp-- ;
  56.                                 //如果分母是0
  57.                                 if ((f > -(1e-6)) && (f < 1e-6))
  58.                                         return -1 ;
  59.                                 *temp /= f ;
  60.                                 temp++ ;
  61.                                 *temp = 0.0 ;
  62.                                 str++ ;
  63.                                 break ;
  64.                         default :
  65.                                 if ((*str >= '0') && (*str <= '9')) {
  66.                                         f = atof(str) ;
  67.                                         pos = Offpos(str) ;
  68.                                         str += pos ;
  69.                                         *temp++ = f ;
  70. //                                        str-- ;
  71.                                 }
  72.                                 break ;
  73.                 }
  74.                 str++ ;
  75.         }
  76.         return *(--temp) ;
  77. }
       主函数代码
  1. int main(int argc, char* argv[])
  2. {
  3.         char datas[1024] = { 0 } ;
  4.         char temp[] = "@-(20+-23*4)/(-1-20/2)@" ;
  5.         float f = 0.0 ;
  6.         Prase(datas, temp) ;
  7.         f = Calculate(datas) ;
  8.         return 0;
  9. }
      程序写得有点乱,经过我简单的测试,目前还没有发现什么问题,如果大家有什么好的建议都可以告诉我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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值