同諸多網友一樣,受益於VCKBASE,覺得應為他做點貢獻了,於是做了這麼一 個基於表達式求值的科學計算器與各位愛好編程的朋友分享。
如您所知,這方面的程序很多,看過ZF.Yi的相關作品,也見過黃江峰的相關 程序,但我覺得我的計算類有不同於二位的特色,如計算結果的有效位較長(16 位);支持不嚴格的表達式輸入(如cos(23)*sin(34)與cos(23)*sin(34與 cos23*sin34等價);支持四種進制的數在一個表達式中同時出現的進制混合運 算(除十進制外的各進制數不限於整數,如12d.3axh,xh是我的計算類所能識別 的十六進制數的標識符);且程序做得也比較精細(如制作了鼠標鍵盤、窗口跟 隨、計算歷史查看等),這才使我覺得拙作不致於濫竽充數,相信網友們看了會 另有收獲的。
一、簡單的思路是這樣的:對於用戶輸入的表達式,
1.將其中的括號按從裡到外,從左到右的順序找到第一對,提取其中的表達 式;
2.將表達式中的所有一元計算部分編譯計算出結果再轉換成字串放回表達式 中;
3.將其中的所有二元計算部分編譯計算出結果再轉換成字串放回表達式中。
4.回到第一步,除非表達式中沒有括號了。
二、實現代碼的一些說明:
以下是計算類中的一個主過程函數:CString CCalculation::MainPro(CString strExp)
{
if(strExp.IsEmpty()) return "表達式不能為空";
Macro(&strExp);
strExp.MakeLower(); //表達式全部小寫
/**********給表達式加上保護括號************/
strExp.Insert(0,"(");
strExp+=")";
/******************************************/
int pos=strExp.Find(" ");
int n=BraCheck(strExp);
CString str;
str.Format("%d",abs(n));
if(n==1) strExp+=")";
else if(n==-1) strExp.Insert(0,"(");
else if(n>0) return "缺少"+str+"個右括號 ";
else if(n<0) return "缺少"+str+"個左括號 ";
while(pos!=-1) //去掉表達式中的空格符
{
strExp.Delete(pos);
pos=strExp.Find(" ");
}
Oct2Dec(&strExp); //將表達式中的八進制數轉換成十進制
Hex2Dec(&strExp); //將表達式中的十六進制數轉換成十進制
Bin2Dec(&strExp); //將表達式中的二進制數轉換成十進制
while(!IsDigital(strExp))
{
DelBracket(&strExp);
if(!SynRes(&strExp)) return strExp;
}
if(!SynRes(&strExp)) return strExp;
else return ModiResult(strExp);
}
首先的Macro(&strExp)是將表達式中的所有常數符號代換為相應的字數 字串;
接著的所謂對表達式兩邊加上保護括號實際上是為了方便對表達式的處理, 因為按照上面所講的思路,後面的二三步其實就是一個對不含括號的表達式的計 算過程,這個過程可以放到第一步裡面去執行,這樣整個對表達式的計算過程就 成了一個不斷去括號,計算括號內的表達式的過程。為整個表達式加上一對括號 就使得我們可以做這樣一個以上形式的循環,則最後一個循環就是對整個表達式 的計算。
在while循環過程中,SynRes(&strExp)用於檢查表達式中是否有ERROE標 記,有的話說明用戶所輸入的表達式有語法錯誤或是表達式的結果有錯(如計算 中遇到了除數為0的情況)。最後的ModiResult(strExp)中對表達式結果的一個 格式化,如將結果科學記數化、提取錯誤信息等。
既然是對字符串表達式求值,整個處理過程中少不了的就是字串到數值,數 值到字串的相互轉換,前者我主要是使用了strtod函數,後者主要是使用了 _ecvt函數,這兩個函數在MSDN中可以查到,這裡我就不細說了。當然轉換過程 光用這兩個函數還不夠,還要有對錯誤表達式的一些控制過程,具體請看源代碼 。
三、結束語
大概情況就是如此,具體的函數處理過程可以參見源代碼,大家有什麼問題 或指正可以與我聯系,謝謝!
四、代碼更新說明
有的網友發郵件給我指出了其中的不足之處,如沒有處理好連加連減或加減 號混合出現的情況(如:1++++1,1----1,--+-+-+1-+-++++---1)。我也發現 了這個問題,所以重寫了其中的MultiE(CString *strExp)計算函數。同時應一 些網友的議建,加入了對結果的十六、八、二進制轉換(以前只能在計算過程中 轉換)。
本文配套源碼