您的位置:首页 > 编程语言 > C语言/C++

C语言 算术表达式

2008-09-09 23:45 274 查看
     算术表达式的计算在我们日常的运用中是十分广泛的,特别是对于基本的四则混合运算的表达式。在我们习惯的计算表达方式中,一般来说是中缀表达式类型的。
     中缀表达式的计算比较复杂,它必须遵守以下三条规则:
     (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 '@' :
             
4000
                   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;
}
      程序写得有点乱,经过我简单的测试,目前还没有发现什么问题,如果大家有什么好的建议都可以告诉我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              
       
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c 语言 算法 float 测试