表达式求值

4 篇文章 0 订阅
/*
本算法的基本思想:把一个表达式A看成是一小段连加或连减的式子,每小段单独处理,
即  A=B +- B +- B...
而每一个B项,看成是一段小连乘或除的式子,每小段单独处理,即
 B=C * / C * / C...
每个C项,看成是一段连乘方的式子,即
C=D ^ D ^ D...
而每个D呢,只有三种不同的情况:一对小括号、一个函数、或者一个普通实数。
用递归函数计算A类式子的值,就可以得到整个表达式的值了。


更快速,更容易的方法是用自动机的思想,把算式的文法写出来,然后根据文法画出
相应的状态转换图(当然文法要满足一定的条件,如不能有左递归等),程序也就出来了。
*/

#define N 10000
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

char s[N+1];//存储表达式的字符串形式
int p;//扫描表达式的指针
char *lib[]={"sin", "cos", "tan", "lg", "ln", "log"}; //支持的函数列表,其中log(a,b) 

double calA(); //计算完整表达式的值,在此声明一下,以用于前向调用,到最后再实现它

double calD() //计算一个数字、函数、或者小括号的值
{
    char fun[4], *tmp;
    int i;
    double a, b;
    
    if(s[p]=='(') //在此处理括号
    {
        p++; //跳过左括号
        return calA(); //括号之内是完整的表达式结构
    }
    else if(s[p]>='a' && s[p]<='z') //出现一个字母,表示这应该是一个函数,做函数处理
    {
        //截取函数名
        for(i=0; s[p]>='a' && s[p]<='z'; p++)
        {
            fun[i]=s[p];
            i++;
        }
        fun[i]='\0';
        								//判断函数名,在此不做错误检查
        i=0;
        while(strcmp(lib[i], fun)!=0)
            i++;
        								//执行函数计算
        p++;							//跳过函数名之后的左括号
        switch(i)
        {
        case 0:
            return sin(calA());
        case 1:
            return cos(calA());
        case 2:
            return tan(calA());
        case 3:
            return log10(calA());
        case 4:
            return log(calA());
        case 5: //这里处理二元函数log(a,b),','分开的两个参数是完整的两个表达式
				//结构
            a=calA();
            b=calA();
            return log(b)/log(a); //对数的换底公式
        }
    }
    else //普通实数,扫描一下就可以了
    {
        a=strtod(s+p, &tmp);
        p=tmp-s;          //用字符指针的减法得到转换中止时的位置
        return a;
    }
}

double calC() 				//计算一个乘方项的值
{
    double a, b;
    a=calD();				//第一个D项的值
    if(s[p]=='^')
    {
        p++;
        return pow(a, calC());//因为乘方是右结合的,所以,要先把右面的值算完才成
    }
    else
        return a;
}

double calB() 								//计算一个乘除项的值
{
    double a, b;
    char c;
    a=calC();								//第一个C项的值
    while(s[p]=='*' || s[p]=='/')
    {
        c=s[p];
        p++;
        b=calC();							//下一个C项的值
        if(c=='*')
            a=a*b;
        else
            a=a/b;
    }
    return a;
}

double calA()								//计算完整表达式的值
{
    double a, b;
    char c;
    a=calB();								//第一个B项的值
    while(s[p]=='+' || s[p]=='-')
    {
        c=s[p];
        p++;
        b=calB();							//下一个B项的值
        if(c=='+')
            a=a+b;
        else
            a=a-b;
    }
    if(s[p]==')' || s[p]==',') //由于括号包括起来的范围也是一个完整的表达式
					//所以要做退括号处理,','是因为对数函数log用它分开两个参数
        p++;
    return a;
}

int main()
{
    scanf("%s", s);
    p=0;
    printf("%lf\n", calA());
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值