#include<iostream>
#include<cmath>
#include<string>
#include<iomanip>
using namespace std;
void menu();//位于calculate函數後面的菜單函數聲明
void guide();//位于主函數後面的指導函數的聲明
double D_Operate(double x,char op,double y)//雙目運算符的運算定義
{
double a;//計算結果
switch(op)
{
case' ': a=x y;break;
case'-': a=x-y;break;
case'*': a=x*y;break;
case'/': a=x/y;break;
case'^': a=pow(x,y);break;//幂運算包括乘方和開方
}//因為都是利用double進行運算 因此不定義取模運算
return a;
}
double S_Operate(char op,double x)//前綴單目運算符的運算定義
{
double a;//計算結果
switch(op)
{
case's': a=sin(x);break;
case'c': a=cos(x);break;
case't': a=tan(x);break;
case'l': a=log10(x);break;//以10為底的對數
case'n': a=log(x);break;//以e(2.718281828)為底的對數
case'_': a=-x;break;//取負用下劃線代替負号 定義為一元運算
}
return a;
}
char Precede(char op1,char op2) //判斷符号的優先級 op1在返回的結果符的左邊 op2在右邊
//用于判定運算符的優先級 以決定是把運算符壓棧 還是把棧内的運算符彈出來進行計算
{
if(((op1==' '||op1=='-')&&(op2==' '||op2=='-'||op2==')'||op2=='='))||\
((op1=='*'||op1=='/')&&(op2==' '||op2=='-'||op2=='*'||op2=='/'||op2==')'||op2=='='))\
||(op1=='^'&&(op2==' '||op2=='-'||op2=='*'||op2=='/'||op2==')'||op2=='='||op2=='s'||op2=='c'||op2=='t'||op2=='_'||op2=='l'||op2=='n'))\
||((op1=='_'||op1=='s'||op1=='c'||op1=='t'||op1=='l'||op1=='n')&&(op2==' '||op2=='-'||op2=='*'||op2=='/'||op2==')'||op2=='='||op2=='s'||op2=='c'||op2=='t'||op2=='_'||op2=='l'||op2=='n')))
return '>';//上述情況下 棧頂運算符優先級高于待定運算符 需彈棧
if((op1=='('&&op2==')')||(op1=='='&&op2=='='))
return '=';
else
return '<';
}
int illegal_char(string s,int i)//非法輸入字符判定函數
{
int j=0;
while(j<i)
{
if(s[j]>='0'&&s[j]<='9')
j ;
else if(s[j]==' '||s[j]=='-'||s[j]=='*'||s[j]=='/'||s[j]=='.'||s[j]=='('||s[j]==')'||s[j]=='^'||s[j]=='!'||s[j]=='e'||s[j]=='_')
j ;
else if((s[j]=='p'&&s[j 1]=='i')||(s[j]=='l'&&s[j 1]=='n'))
j =2;
else if((s[j]=='s'&&s[j 1]=='i'&&s[j 2]=='n')||(s[j]=='c'&&s[j 1]=='o'&&s[j 2]=='s')||(s[j]=='t'&&s[j 1]=='a'&&s[j 2]=='n')||(s[j]=='l'&&s[j 1]=='o'&&s[j 2]=='g'))
j =3;
//以上都是标準的數字字符和運算符 如若存在其他形式的字符 則是非法輸入
else
{
cout<<"程序終止,存在非法的字符輸入!!!"<<endl;
return 0;
}
}
return 1;//沒有非法字符 返回1 否則返回0
}
int match(string s)//棧結構的括号匹配檢測函數
{
int i=0,top=0;
char stack[50];
while(s[i]!='\0')
{
if(s[i]=='(')
{
stack[top]=s[i];
top ;
}
//push 左括号壓入棧内
if(s[i]==')')
if(stack[top-1]=='(')
{
int a=i 1;
stack[top-1]=NULL;
top--;
}//把與右括号匹配的左括号彈掉
else
{
cout<<"括号輸入有誤"<<endl;
return 0;//多了右括号 括号失陪 返回非法
}//pop'('
i ;
}
if (top!=0)
{
cout<<"括号輸入有誤"<<endl;
return 0;//多了左括号 括号失陪 返回非法
}
return 1;//返回合法
}
class NUMstack//運算數棧
{
public:
double num[1000];
int top;
void start()//初始化棧清空棧頂指針置底
{
for(int i=0;i<1000;i )
num[i]=0;
top=0;
}
void push(char a)//因為有多位數的運算因此不能一壓棧就提升棧頂指針
{
num[top]=num[top]*10 (a-'0');//把字符轉成數因為每次入棧之前要乘10 所以初始化要清0
}
double pop()
{
top--;
double number=num[top];
num[top]=0;
return number;
}//彈棧函數 彈掉棧頂元素 棧頂歸0 top指針下降
double getTop()//取棧頂元素但不必彈棧
{return num[top-1];}
void lift()//提升top指針的函數
{top ;}
};
class OPERstack//運算符棧
{
public:
char oper[1000];
int top;
void start()//初始化函數棧清空棧底放一"="用于判定算式結束
{
oper[0]='=';
for(int i=1;i<1000;i )
oper[i]=NULL;
top=1;//棧頂指針置于棧底的上一位
}
void push(char a)
{
oper[top]=a;
top ;//與數字棧不同一壓棧就可以提升指針
}
char pop()
{
top--;
char op=oper[top];
oper[top]=NULL;
return op;//彈出計算符 用于計算
}
char getTop()
{
return oper[top-1];//取棧頂符号 但不彈棧 可用于判定優先級
}
};
void calculate(string equation)//算式計算函數(關鍵函數)
{
NUMstack number;//定義運算數棧變量number
OPERstack oper;//定義運算符棧變量oper
number.start();
oper.start();//把兩個棧初始化
int i=0,len=0,k;
char p,sig;
double yuan1,yuan2;
while(equation[i]!='\0')
{
len ;
i ;
}//計算等式長度len
if(equation[len-1]!='=')
{
cout<<"輸入有誤沒有輸入終止符号--等号"=""<<endl;
return;//檢測有沒有結束符等号"="
}
int le;
le=illegal_char(equation,len-1);
if(le==0)
return;//有非法字符 不進行後續計算
le=match(equation);
if(le==0)
return;//括号匹配非法 不進行後續計算
for(i=0;i<len;i )//初步确定合法後開始計算算式
{
if(equation[i]=='!')//階乘是後綴單目運算符單獨進行計算
{
yuan1=number.pop();//彈出棧頂元素做階乘
if (yuan1==0)
{
number.num[number.top]=0;//0的階乘為0 壓結果入棧
number.lift();
}
else
{
number.num[number.top]=1;
for(k=1;k<=yuan1;k )//階乘循環
number.num[number.top]=k*number.num[number.top];
number.lift();//結果入站
}
}
else if(equation[i]>='0'&&equation[i]<='9')
{
number.push(equation[i]);//壓數字字符入棧
if((equation[i 1]<'0'||equation[i 1]>'9')&&equation[i 1]!='.')
number.lift();//當整個多位運算數讀取完畢後,運算數棧棧頂指針才能提升
}
else if(equation[i]=='p')
{
number.num[number.top]=3.1415926536;//pi值即π 圓周率 要壓入數字棧
number.lift();
i ;//pi是兩個字符所以要移動掃描算式的指針往後跳一個
}
else if(equation[i]=='e')
{
number.num[number.top]=2.718281828459;//e 自然對數底數 壓入運算數棧
number.lift();
}
else if(equation[i]=='.')//小數壓棧代碼
{
int x=1;
while(equation[i x]>='0'&&equation[i x]<='9')
{
number.num[number.top] =((equation[i x]-'0')/pow(10,x));//第x位小數入棧
x ;
}
x--;
number.lift();
i=i x;
}
else if(equation[i]=='(')
{
oper.push(equation[i]);//左括号無條件壓棧
}
else//數階乘左括号判斷完畢後其他運算符的分類讨論
{
if(oper.top==1)//運算符棧為空運算符可以無條件入棧
{
if(equation[i]=='l'&&equation[i 1]=='o')
oper.push('l');
else if(equation[i]=='l'&&equation[i 1]=='n')
oper.push('n');//因為log和ln都是小寫字母l開頭所以要分情況讨論
else
oper.push(equation[i]);
}
else//運算符棧不為空則要進行優先級判斷
{
char temp1=oper.getTop();//取出棧頂符号
char temp2;//待入棧符号
if(equation[i]=='l'&&equation[i 1]=='o')
temp2='l';
else if(equation[i]=='l'&&equation[i 1]=='n')
temp2='n';//log與ln的再次讨論
else
temp2=equation[i];
p=Precede(temp1,temp2);
if(p=='<')
oper.push(temp2);//棧頂符優先級較低現在待定的運算符就可以入棧了
if(p=='>'||p=='=')
{
char rep=p;//當棧頂符優先級不低于待入棧的符号 則運算符棧不停地彈棧
//進行運算直到低于待入棧符号為止 rep用于記錄比較結果 要多次進行判斷
while((rep=='>'||p=='=')&&(oper.top-1>0))
{
sig=oper.pop();
yuan1=number.pop();
yuan2=number.getTop();//靠前的一個運算數隻要取得不要彈出來
if(sig=='/'&&yuan1==0)//yuan1是雙目運算符後面的第二運算元
{
cout<<"計算時出錯!!出現了除數為0的情況!!"<<endl;
return;
}
if(sig=='^'&&yuan2<0&&yuan1>0&&yuan1<1&&(static_cast <int>(1/yuan1))%2==0)
//對負數開偶次根号的限制
{
cout<<"計算時出錯!!出現了負數開偶次根号的情況!!"<<endl;
return;
}
if(sig=='_'||sig=='s'||sig=='c'||sig=='t'||sig=='l'||sig=='n')//若為前綴單目運算符
{
double tt;
tt=S_Operate(sig,yuan1);
number.num[number.top]=tt;//運算結果壓回原來yuan1在棧内的位置
number.lift();//提升指針
temp1=oper.getTop();
rep=Precede(temp1,temp2);//再判優先級
}
else
{
number.num[(number.top)-1]=D_Operate(yuan2,sig,yuan1);
temp1=oper.getTop();
rep=Precede(temp1,temp2);//雙目運算符的計算
}
}
if(equation[i]==')')//如果棧外符是右括号要把與之匹配的左括号彈出棧外
oper.pop();
else if(equation[i]=='l'&&equation[i 1]=='o')
oper.push('l');//代表log的l
else if((equation[i]=='l')&&(equation[i 1]=='n'))
oper.push('n');//代表ln的n
else
oper.push(equation[i]);
}
}
if(equation[i]=='s'||equation[i]=='c'||equation[i]=='t'||(equation[i]=='l'&&equation[i 1]=='o'))
i=i 2;
if(equation[i]=='l'&&equation[i 1]=='n')
i ;
//對于不止一個字符的運算符 sin log ln等等 要移動掃描算式的指針 往後跳一個或兩個
}
}
if(number.num[0]==ceil(number.num[0]))
cout<<equation<<number.num[0]<<endl;
else
{cout<<equation<<fixed<<setprecision(8)<<number.num[0]<<endl;}//輸出結果控制精度8位小數
//調試時檢查運算結束後站内情況的代碼段
}
void menu()//菜單函數
{
cout<<"實數型科學算式計算器"<<endl;
cout<<"(徐州工業職業技術學院 混子)"<<endl;
cout<<endl;
cout<<"歡迎使用o(∩_∩)o !!!"<<endl;
cout<<"請選擇你需要的功能:(0,1或者2)"<<endl;
cout<<"----------"<<endl;
cout<<"1.使用說明"<<endl;
cout<<"2.計算算式"<<endl;
cout<<"0.退出程序"<<endl;
cout<<"----------"<<endl;
cout<<"你的選擇是:";
int choice;
cin>>choice;
switch(choice)
{
case 0:return;
case 1:guide();break;
case 2:
{
system("cls");
char go_on='y';
string equation;
while(go_on=='y')
{
cout<<endl<<endl<<"請輸入算式,以=(等号)結束:"<<endl;
cin>>equation;
calculate(equation);
cout<<"繼續使用嗎?是請輸入y 否則輸入n:";
cin>>go_on;//可以循環進行算式計算
}
system("cls");
menu();
}
}
}
void main()
{
menu();
}
void guide()//輸入規則介紹說明書
{
system("cls");
cout<<"使用說明:"<<endl;
cout<<"輸入算式時,請按照下列規則輸入:"<<endl;
cout<<"1.四則運算 加 -減 *乘 /除按常規輸入,負号用下劃線(_)代替,注意将其與減号區别;可用括号()界定優先級"<<endl;
cout<<"2.^幂:幂運算如下乘方輸入x^y(x的y次方)如23^6就是23的6次方;開方也這樣輸入如81^(1/4)[或者81^0.25]表示81開4次方"<<endl;
cout<<"3.!階乘:6!表示1*2*3*4*5*6;(1 3)!表示4的階乘,結果是24;1 3!表示1再加上3做階乘的結果,是7"<<endl;
cout<<"4.pi代表圓周率,即3.1415926536,本計算器利用弧度進行三角函數計算;計算正弦請輸入sin,餘弦輸入cos,正切輸入tan;sin(pi/2)就是二分之π弧度對應的正弦值(注意一定要打括号)其他依此類推;"<<endl;
cout<<"5.計算以10為底的對數請輸入log,如log1000=3,計算以e(2.718281828)為底的自然對數請輸入ln,如lne^4=4,注意指數的輸入要規範,如lne^4=4,但是(lne)^4=1,計算算式的對數要在對數符号後面把算式括起來,如ln(3 6*9),計算以其他數為底的對數可利用對數換底公式,如以2為底,16的對數可輸入ln16/ln2或者log16/log2結果都是4"<<endl;
cout<<"6.可直接輸入e和pi做數值計算"<<endl;
cout<<"7.本計算器的括号隻有小括号();不接受中括号[ ]和大括号{ },且算式一定要以等号(=)結束"<<endl;
system("pause");
system("cls");
menu();
}
,
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!