科學計算器學生時代小作品原始碼(C++版)
/*************************************************************************************
簡易科學計算器
made by:danyuan
專業:12級——資訊工程2班
學校:湖南理工學院
//功能說明:
1.可以進行帶括號的表示式運算;
2.可以檢查並識別更改表示式錯誤:
(1.對於非法字元,報錯處理
(2.對於括號不匹配,報錯處理
(3.對於數字或右括號接左括號,自動在中間補乘號
3.可以進行負數運算;
中綴表示式規則///
操作符特性:
0.表示式第一個字元不能為*、/、^、!、)
1.+、-、*、/這類操作符不能連續兩個在一起,後面不能接')'、'!'
2.'('後面不能接+、*、/、!這些符號,如果後面是‘-’,則認為是負號
3.'!'後面不能接數字,可以接其它操作符,如果不是!和^則在中間自動補乘號
4.'^'後面不能接任何操作符除了‘(’
5.單向右操作符後面只能接同類操作符或數字、(。例如:開方、取反、求倒數、三角函式等
6.單向左操作符後面不能接數字,如果是同類操作符繼續操作,如果是‘(’或其他操作符中間新增乘號
7.括號必須配對
總結:大體目前可以分為四類:
即:接雙運算元的操作符、接左運算元的單操作符、接右運算元的單操作符、雙向都可接的單操作符(此類
暫不談論,看情況而定)
*************************************************************************************/
先上圖:
當然這是美化後的科學計算器,下面是基礎計算器的程式碼:
#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
相關文章
- MATLAB R2023a:引領科學計算與資料分析的新時代 mac/win版MatlabMac
- 開啟全民程式設計時代!Python小學生都要學的程式語言!程式設計Python
- python中小學生程式設計學習-政策定了,中小學生學習程式設計不得少於36小時,全民程式設計時代來了...Python程式設計
- NumPy科學計算庫
- 專科生學習雲端計算就業前景如何?就業
- 學習雲端計算簡單嗎?專科生學習雲端計算就業前景如何?就業
- 資料科學即將迎來“無程式碼”時代資料科學
- AI for Science,開啟智慧科學時代!AI
- Python科學測量與計算庫Pymeasure: 控制你的儀器進行自動測試和科學計算Python
- 一個計算機學生計算機
- 編譯原理——C++版桌面計算器編譯原理C++
- 專科學歷去學計算機,前景到底如何?計算機
- [python][科學計算][matplotlib]使用指南Python
- [python][科學計算][pandas]使用指南Python
- [python][科學計算][numpy]使用指南Python
- Wolfram Mathematica 13(科學計算軟體)
- 專科生該選擇學習雲端計算還是web前端Web前端
- 小學生學習C++應該具備哪些基礎?C++
- 大學生適合學雲端計算嗎?
- C++簡易計算器自寫棧版C++
- Java 學生管理系統(MVC)開源原始碼(基礎版)JavaMVC原始碼
- Wolfram Mathematica 13 (科學計算軟體)13.3.1中文啟用版
- 雲端計算學習路線原始碼框架筆記:Mysql原始碼一原始碼框架筆記MySql
- 雲端計算學習路線原始碼框架筆記:Mysql原始碼二原始碼框架筆記MySql
- 雲端計算學習路線原始碼框架筆記:Mysql原始碼三原始碼框架筆記MySql
- 入選《時代》的科學牛人,人工智慧和機器學習最權威的學者之一人工智慧機器學習
- 10大Python資料科學原始碼教程Python資料科學原始碼
- Python科學計算之Numpy陣列生成與運算Python陣列
- Python 計算生態中那些著名的庫-機器學習Python機器學習
- Vue原始碼學習(十七):實現computed計算屬性Vue原始碼
- 雲端計算時代前端如何保證開原始碼的安全性前端原始碼
- 小學生學習設計模式之單例模式設計模式單例
- Composition實現科學文字計數器
- MATLAB R2023a:資料科學和數學計算的突破性進展 mac/win版Matlab資料科學Mac
- 計算機密碼學01計算機密碼學
- 一個專科出來的計算機學生,月薪兩萬是否不切實際?計算機
- 科學計算教你顯示器尺寸怎麼選 顯示器多大尺寸合適?
- 【PAT乙級、C++】1024 科學計數法 (20分)C++