科学计算器学生时代小作品源码(C++版)

/*************************************************************************************

                                                                 简易科学计算器

                                                                           made by:danyuan

                                                                           专业:12级——信息工程2班

                                                                           学校:湖南理工学院

//功能说明:

         1.可以进行带括号的表达式运算;

         2.可以检查并识别更改表达式错误:

                   (1.对于非法字符,报错处理

                   (2.对于括号不匹配,报错处理

                   (3.对于数字或右括号接左括号,自动在中间补乘号

         3.可以进行负数运算;

         中缀表达式规则///

         操作符特性:

         0.表达式第一个字符不能为*、/、^、!、)

         1.+、-、*、/这类操作符不能连续两个在一起,后面不能接')'、'!'

         2.'('后面不能接+、*、/、!这些符号,如果后面是‘-’,则认为是负号

         3.'!'后面不能接数字,可以接其它操作符,如果不是!和^则在中间自动补乘号

         4.'^'后面不能接任何操作符除了‘(’

         5.单向右操作符后面只能接同类操作符或数字、(。例如:开方、取反、求倒数、三角函数等

         6.单向左操作符后面不能接数字,如果是同类操作符继续操作,如果是‘(’或其他操作符中间添加乘号

         7.括号必须配对

 

  总结:大体目前可以分为四类:

 

                   即:接双操作数的操作符、接左操作数的单操作符、接右操作数的单操作符、双向都可接的单操作符(此类

 

暂不谈论,看情况而定)

*************************************************************************************/

先上图:

科学计算器学生时代小作品源码(C++版)

科学计算器学生时代小作品源码(C++版)

科学计算器学生时代小作品源码(C++版)

当然这是美化后的科学计算器,下面是基础计算器的代码:

#ifndef CACULATOR_H

#define CACULATOR_H

#include "DYHeaderFile/stack.h"

 

template<class T>

class DYCaculator{

protected:

         char *middlestr;//中缀式字符串

         char *backstr;//后缀式字符串

         T m_result;       //存放运算结果

         stack<T> numstack;//用于存放操作数的栈

         stack<char> operatestack;//用于存放操作符号的栈

 

         static        char m_symbolarr[255];//基本计算器能识别的符号

public:

         /工具类函数///

         static T factoria(T num);//阶乘,特点:接左操作数的操作符!表示和^同级

 

         /框架计算函数/

         DYCaculator(char *str);

         DYCaculator()//重载构造函数

         {

                   middlestr=NULL;

                   backstr=NULL;

                   m_result=0;

         }

         ~DYCaculator();

         virtual bool SetText(char * a);

         T GetResult();

         bool GetBackStr();

         virtual bool Caculating();

         virtual T DealFun(char c);

         virtual bool CheckOperator();

         virtual void SetSinFlag(bool flag)=0;//设置角度还是弧度运算

         //工具函数/

         virtual int GetClass(char a);//返回分类

         int JungdeLevel(char a);//判断优先级

         int GetNumClass(char a);//返回分类,只为GetNum函数服务

         T GetNum(char *str);//根据字符串返回其数值

         void IverseStr(char *str);

         void Ttostr(T num,char *str);//从某个数值转换为字符串

         bool strequal(char *a,char *b);//忽略大小写的字符串判等函数

};

//工具函数

template<class T>

int DYCaculator<T>::GetClass(char a)//返回分类

{

         char arr1[]="1234567890";

         char arr2[]="+-*/()^!";//同类不能叠加(特殊另作处理),后可以接子类操作符

         int flag=-1,i;

 

         for(i=0;i<(int)(strlen(arr1));i++)

                   if(a==arr1[i])

                            flag=1;//表明是数字

 

         if(a=='.')

                   flag=2;//表明是小数点

        

         for(i=0;i<(int)(strlen(arr2));i++)

                   if(a==arr2[i])

                            flag=3;//表明是操作符

         //子类可重写单操作符的处理

 

         return flag;

}

template<class T>

char DYCaculator<T>::m_symbolarr[255]="0123456789+-*/()^.!";//abcdefghijklmnopqrstuvwxyz//a~z代表可以支持26个附

 

加操作或函数

template<class T>

DYCaculator<T>::DYCaculator(char *str)//生成对象时,传入一个操作指令,进行分配内存、获得操作指令

{

         middlestr=new char[strlen(str)*2];

         strcpy(middlestr,str);

         backstr=new char[2*strlen(str)];

         backstr[0]='\0';

         m_result=0;

}

 

template<class T>

bool DYCaculator<T>::SetText(char * str)//后面调用,传入一个操作指令,进行分配内存、获得操作指令

{

         if(middlestr)//如果原来已经分配了内存

                   delete []middlestr;//释放原有内存

         if(backstr)

                   delete []backstr;

         middlestr=new char[strlen(str)*2];

         if(!middlestr)

                   return false;//若分配内存失败,则报错

         strcpy(middlestr,str);

         backstr=new char[2*strlen(str)];

         if(!backstr)

                   return false;//若分配内存失败,则报错

         backstr[0]='\0';//清空该字符串

         m_result=0;//初始化

         numstack.clear();

         operatestack.clear();

         return true;

}

template<class T>

DYCaculator<T>::~DYCaculator()//释放动态分配的内存

{

         delete []middlestr;

         delete []backstr;

}

 

template<class T>

bool DYCaculator<T>::CheckOperator()//检验输入表达式合法性

{

         stack<char> teststack;//匹配'('、')'

         int i=0,j=0;

         int len=strlen(middlestr);

         int symbolstrlen=strlen(m_symbolarr);

         bool chflag=false;

         //0.第一个字符不能为*、/、^、!、)

         char arr[6]="*/^!)";

         for(i=0;i<5;i++)

                   if(middlestr[0]==arr[i])

                            return false;

         for(i=0;i<len;i++)

         {

                   //1.检查是否有非法字符出现在表达式中

                   chflag=false;//合法符号标志位

                   for(int m=0;m<symbolstrlen;m++)

                            if(middlestr[i]==m_symbolarr[m])

                                     chflag=true;

                   if(!chflag)

                            return false;

                   //2.利用栈判断括号是否配对

                   if(middlestr[i]=='(')

                            teststack.push('(');

                   if(middlestr[i]==')')

                   {

                            if(teststack.empty())//如果没有左括号,则表达式有误

                                     return false;

                            teststack.pop();//弹出'('

                   }       

                   //3.自动添加乘号,即:1.')'紧接'('、 2.数字紧接'('、 3.')'接数字、4.数字接右单操作符, 中间自动补

 

乘号

                   int addflag=false;

                   if(GetClass(middlestr[i])==1||(middlestr[i]==')'))//如果是数字

                   {

                            if(middlestr[i+1]=='(')//||((middlestr[i]==')')&&(GetClass(middlestr[i+1])==1))||

 

((GetClass(middlestr[i+1])==4)))//则判断为乘号,自动为表达式添加乘号

                                     addflag=true;

                            if(middlestr[i]==')'&&(GetClass(middlestr[i+1])==1||(GetClass(middlestr[i+1])==4)))//右

 

括号后接数字或左单向操作符添乘号

                                     addflag=true;

                            if(GetClass(middlestr[i])==1&&(GetClass(middlestr[i+1])==4))

                                     addflag=true;

                   }

                   if(middlestr[i]=='!'&&(GetClass(middlestr[i+1])==1||(middlestr[i+1]=='(')))//'!'后面接数字和'('

 

自动补乘号

                   {

                            addflag=true;

                   }

                   //为有需要的地方添加乘号,属于步骤3

                   if(addflag)

                   {

                            int k=0;

                            for(k=len;k>i;k--)//元素后移,腾出空位

                            {

                                     middlestr[k+1]=middlestr[k];

                            }

                            middlestr[++k]='*';//添加乘号

                            middlestr[++len]='\0';

                   //      cout<<middlestr<<endl;//测试之用

                   }

 

                   //4.检查是否有操作符紧接操作符(预判操作i+1),即:四则运算符之间要隔开、四则运算符不能接')'等

 

                   if(GetClass(middlestr[i])==3)//如果是操作符

                   {

                            if(middlestr[i]=='!')

                            {

                                     if(GetClass(middlestr[i+1])==1)//阶乘符号后面不能接数字

                                               return false;

                            }

                            else if(middlestr[i]=='(')//左括号后面不可直接接双操作符

                            {

                                     if(GetClass(middlestr[i+1])==3&&(middlestr[i+1]!='(')&&(middlestr[i+1]!=')')&&

 

(middlestr[i+1]!='-'))

                                               return false;

                            }

                            else if(middlestr[i]==')')//右括号所有操作符都可以接

                            {

                           

                            }

                            else

                            {

                                     if(GetClass(middlestr[i+1])==3&&(middlestr[i+1]!='('))

                                               return false;//如果四则运算符号后面紧接四则运算符号,则表达式有误

                            }

                   }

 

                   //5.如果是单操作符,方式又不一样了

                   if(GetClass(middlestr[i])==4)

                   {

                            //1.单操作符后不能接操作符(除‘(’)

                            if(GetClass(middlestr[i+1])==3&&(middlestr[i+1]!='(')||(GetClass(middlestr[i+1])==4))

                                     return false;

                   }

        

         }

         if(!teststack.empty())

                   return false;//如果栈不为为空,则配对失败,此操作属于步骤2

 

         return true;

}

 

template<class T>

T DYCaculator<T>::GetResult()

{

         cout<<"有什么不懂的,或是想交流编程心得的人";

         cout<<endl<<"欢迎大家"<<"加我"<<"企鹅群:320540648"<<endl;

         return m_result;

}

 

template<class T>

bool DYCaculator<T>::GetBackStr()//获得后缀表达式

{

         int i=0,j=0,flag=0;

         int len=strlen(middlestr);

         int reallen=0;//后缀式字符串实际长度

         bool separetflag=0;

         for(i=0;i<len;i++)

         {

                   flag=GetClass(middlestr[i]);

                   if(flag==3||(flag==4))//一. 如果是操作符,就判断优先级入栈或出栈

                   {

                            //(1.分隔两个操作数字符串

                            if(separetflag==1)//如果前面有数字,添加分隔符

                            {

                                     backstr[reallen++]='|';

                                     separetflag=0;

                            }

                            //(2.对操作符优先级的判断,即:

                                               //1.前后两操作符之间的优先级判断(前者先出栈,若后者优先级高,则后者入

 

栈,否者前者出栈);

                                               //2.若遇到左括号,直接入栈(优先级最高),遇到右括号,操作符连续出栈,

 

直到弹出一个左括号为止,弹出的四则运算符添加到后缀式末尾;

                                               //3.智能识别负号,用#号代替负号

                            if(operatestack.empty())//如果操作符栈为空,则直接入栈

                                     operatestack.push(middlestr[i]);

                            else

                            {

                                     if(middlestr[i]=='(')//如果是左括号,且后面是减号,则为后面的数添加一个负号

                                     {

                                               operatestack.push(middlestr[i]);//先入栈

                                               if(middlestr[i+1]=='-')

                                               {

                                                        backstr[reallen++]='#';//代表这是负号,不是减号

                                                        i++;

                                                        continue;

                                               }

                                     }

                                     else if(middlestr[i]==')')//如果为右括号,则出栈,直到弹出一个左括号为止

                                     {

                                               while(!operatestack.empty()&&(operatestack.gettop()!='('))//依次弹出栈

 

内的符号

                                               {

                                                        backstr[reallen++]=operatestack.gettop();

                                                        operatestack.pop();

                                               }

                                               operatestack.pop();//弹出'('

                                     }

                                     else

                                     {

                                               //如果栈内符号优先级大于当前符号,则依次出栈

                                               while(!operatestack.empty()&&(JungdeLevel(operatestack.gettop())

 

>=JungdeLevel(middlestr[i]))&&(operatestack.gettop()!='('))

                                               {

                                                        backstr[reallen++]=operatestack.gettop();

                                                        operatestack.pop();

                                               }

                                               //否则就入栈

                                               operatestack.push(middlestr[i]);

                                     }

                            }

                   }

                   else//二.是操作数中的字符

                   {

                            backstr[reallen++]=middlestr[i];

                            separetflag=1;

                   }

         }

         while(!operatestack.empty())//如果栈内还有操作符,则依次全部出栈

         {

                   backstr[reallen++]=operatestack.gettop();

                   operatestack.pop();

         }

         backstr[reallen]='\0';

         return true;

}

template<class T>

bool DYCaculator<T>::Caculating()//计算后缀式并获得结果

{

         GetBackStr();//转为后缀式

         int i=0,j=0;

         int pos=0;

         int backreallen=strlen(backstr)+1;

         char arr[100];

         bool numflag=false;

 

         for(i=0;i<backreallen;i++)

         {                

                   //1.如果是操作符,则将栈顶两个元素取出进行四则运算

                   if(GetClass(backstr[i])==3||(GetClass(backstr[i])==4))//如果是四则运算符号

                   {

                            if(numflag)//如果后面是操作符,则将操作数入栈

                            {

                                     numflag=false;

                                     arr[j]='\0';

                                     numstack.push(GetNum(arr));//根据字符串获得数值并将数值压入栈中

                                     j=0;//初始化

                            }                          

                            numstack.push(DealFun(backstr[i]));//将运算结果压入栈中

                   }//2.如果是分隔符或结尾符,判断其前面是否有操作数字符串,如果有就将操作数字符串转化为数字后入栈

                   else if(backstr[i]=='|'||(backstr[i]=='\0'))//如果后面是分隔符或结尾符,将操作数入栈

                   {       

                            if(numflag)//将操作数入栈

                            {

                                     numflag=false;

                                     arr[j]='\0';

                                     numstack.push(GetNum(arr));

                                     j=0;//初始化

                            }

                   }

                   else //3.生成数字字符串,即:用一个字符串来保存操作符含有的字符

                   {

                            if(backstr[i]=='#')//代表负数,如果是负数,前面加负号

                            {

                                     arr[j++]='-';

                                     continue;

                            }

                            arr[j++]=backstr[i];//如果是数字,则加入数字字符串

                            numflag=true;//代表有数字还未入栈

                   }

         }

 

         m_result=numstack.gettop(); 

         return true;

}

template <class T>

T DYCaculator<T>::DealFun(char c)

{

         bool doubleOrSingle=false;//初始化为双操作数

         T operate1=0,operate2=0,result=0;

         //判断是单操作数还是双操作数.....(单操作数只需弹出一个操作数,否则两个)

         if(c=='!')

                   doubleOrSingle=true;

        

         if(doubleOrSingle)//单操作数的情况

         {

                   if(c=='!')

                   {

                            result=factoria(numstack.gettop());

                            numstack.pop();

                   }

         }

         else//此处是双操作数的情况

         {

                   if(!numstack.empty())

                            {

                                     operate1=numstack.gettop();

                                     numstack.pop();

                            }

                            else

                            {

                                     if(c=='-'||(c=='+'))

                                               operate1=0;

                                     else

                                               operate1=1;

                                    

                            }

                            if(!numstack.empty())

                            {

                                     operate2=numstack.gettop();

                                     numstack.pop();

                            }

                            else

                            {

                                     if(c=='-'||(c=='+'))

                                               operate2=0;

                                     else

                                     {

                                               operate2=operate1;

                                               operate1=1;

                                     }

                                    

                            }

                            switch(c)

                            {

                            case '-':result=operate2-operate1;break;

                            case '+':result=operate2+operate1;break;

                            case '*':result=operate2*operate1;break;

                            case '/':

                                     if(operate1!=0)

                                               result=operate2/operate1;

                                     else

                                               return 0;//分母为零时操作失败

                                     break;

                            case '^':result=pow((double)operate2,(double)operate1);break;

                   }

         }

                            return result;

}

//计算功能函数//

template<class T>

T DYCaculator<T>::factoria(T num)//阶乘,特点:接左操作数的操作符!表示和^同级

{

         if(num<=0)

                   return (T)0;

         if(num==1)

                   return 1;

         for(int i=(int)(num-1);i>0;i--)

                   num*=(T)i;

         return num;

}

//工具函数//

template<class T>

int DYCaculator<T>::JungdeLevel(char a)//判断优先级

{

         char arr[]="abcdefghijk";//比*、/优先级高

         for(int i=0;i<(int)(strlen(arr));i++)

                   if(a==arr[i])

                            return 3;

         if(a=='+'||(a=='-'))

                   return 0;

         else if(a=='*'||(a=='/'))

                   return 2;

         else if(a=='^'||a=='!')

                   return 4;

         else

                   return 5;//否者为括号,为*

}

 

template<class T>

int DYCaculator<T>::GetNumClass(char a)//返回分类,只为GetNum函数服务

{

         char arr1[]="1234567890";

         char arr2[]=".";

         int flag=-1,i;

 

         for(i=0;i<(int)(strlen(arr1));i++)

                   if(a==arr1[i])

                            flag=1;//表明是数字

 

         if(a=='.')

                   flag=2;//表明是小数点

        

         return flag;

}

template<class T>

T DYCaculator<T>::GetNum(char *str)//根据字符串返回其数值

{

         T result=0;

         T t1=0,t2=0;

         int len=strlen(str);

         int i=0,flag=0,j=1;

        

         for(i=0;i<len;i++)

         {

                   if(GetNumClass(str[i])==2)

                            flag=1;

                   if(GetNumClass(str[i])==1)

                   {

                            if(!flag)

                                     t1=t1*10+(str[i]-'0');

                            else

                            {

                                     t2=t2*10+(str[i]-'0');

                                     j*=10;//判断小数点向后移动的位数

                            }

                   }       

         }

         result=t1+(t2/j);//整数部分加上小数部分

         if(str[0]=='-')

                   result*=-1;

         return result;

}

template<class T>

void DYCaculator<T>::IverseStr(char *str)//字符串翻转

{

         int i=0,len=strlen(str);

         char c;

         for(i=0;i<((len+1)/2);i++)

         {

                   c=str[i];

                   str[i]=str[len-i-1];

                   str[len-i-1]=c;

         }

                  

}

template<class T>

void DYCaculator<T>::Ttostr(T num,char *str)//从某个数值转换为字符串,存在精度损失,不可取

{

         int i=0,j=0;

         int tnum=(int)num,tmod=1;

         while(tnum>0)

         {

                   str[i++]=tnum%10+'0';//返回字符

                   tnum/=10;

         }

         str[i]='\0';

         IverseStr(str);

         str[i++]='.';

         for(j=0;j<6;j++)//精确到小数点后6位即可

         {

                   tnum=(int)(num*10)%10;

                   str[i++]=tnum+'0';

                   num*=10;

         }

         str[i]='\0';

}

template<class T>

bool DYCaculator<T>::strequal(char *a,char *b)//忽略大小写的字符串判等函数

{

         int i=0,j=0;

         bool flag=true;

         if(strlen(a)!=strlen(b))//如果长度不等,则不相等

                   return false;

         for(i=0;a[i]!='\0'&&(b[i]!='\0');i++)

         {

                   //忽略大小写进行比较

                   if(a[i]!=b[i]&&(a[i]!=(b[i]+('A'-'a')))&&(a[i]!=(b[i]-('A'-'a'))))

                   {

                            return false;

                   }

         }

         return true;

}

#endif