c++生成算式並計算(《構建之法》第一章課後第一題)
阿新 • • 發佈:2018-10-31
c++實現計算器(自動生成算式並計算)
要滿足的需求有以下幾個:
- 自動生成隨機的四則運算算式,包含括號和小數。
- 對生成的算式計算出結果。
- 算式、結果分別儲存到不同的檔案。
一 生成算式
由上述需求可知,算式中有運算子('+','-','*','/','(',')'),整數,小數(重點是有小數點),同時滿足程式模組化設計的要求,所以使用STL中的string類儲存生成的算式。
生成算式時有幾點需要注意:
- 首先生成一個數字,然後運算子('+','-','*','/')和數字交替出現,可以限定長度為奇數,在偶數位置(位置從0開始)生成數字,奇數位置生成運算子。
- 生成數字有整數有小數。使用一個隨機變數控制生成的小數和整數的比例。
- 生成小數時控制好位數、大小。
- 生成括號時注意一個左括號一定要有一個右括號對應,因此設定一個變數儲存剩餘要生成的右括號的數量,即每生成一個左括號該變數加一,沒生成一個右括號該變數減一。同時控制除非到了算式最後,不會出現一對括號只括住一個數字的情況。
在程式中,以上這些由string GenerateExpression()
實現,同時它還會呼叫int GenerateRightBracket()
,int GenerateLeftBracket()
,char GenerateOperator()
,double GeneratNumber()
,int GenerateInt()
。
二 中綴表示式轉為逆波蘭式
逆波蘭式即字尾表示式,棧可以方便的在計算機中計算字尾表示式的值。
將一個普通的中序表示式轉換為逆波蘭表示式的一般演算法是:
首先需要分配2個棧,一個作為臨時儲存運算子的棧S1(含一個結束符號),一個作為輸入逆波蘭式的棧S2(空棧),S1棧可先放入優先順序最低的運算子#,注意,中綴式應以此最低優先順序的運算子結束。可指定其他字元,不一定非#不可。從中綴式的左端開始取字元,逐序進行如下步驟:
- 若取出的字元是運算元,則分析出完整的運算數,該運算元直接送入S2棧
- 若取出的字元是運算子,則將該運算子與S1棧棧頂元素比較,如果該運算子優先順序(不包括括號運算子)大於S1棧棧頂運算子優先順序,則將該運算子進S1棧,否則,將S1棧的棧頂運算子彈出,送入S2棧中,直至S1棧棧頂運算子低於(不包括等於)該運算子優先順序,最後將該運算子送入S1棧。
- 若取出的字元是“(”,則直接送入S1棧頂。
- 若取出的字元是“)”,則將距離S1棧棧頂最近的“(”之間的運算子,逐個出棧,依次送入S2棧,此時拋棄“(”。
- 重複上面的1~4步,直至處理完所有的輸入字元
- 若取出的字元是“#”,則將S1棧內所有運算子(不包括“#”),逐個出棧,依次送入S2棧。
以上來自逆波蘭式-百度百科,完成以上步驟,S2棧便為逆波蘭式輸出結果。不過S2應做一下逆序處理。
在本程式中,使用佇列(queue)取代棧S2,省去逆序處理的步驟,這些步驟由函式queue<string> ConvertToRpn(string s,map<string,int>p,map<char,int>p_char)
實現。
三 計算逆波蘭式
新建一個表示式,如果當前字元為變數或者為數字,則壓棧,如果是運算子,則將棧頂兩個元素彈出作相應運算,結果再入棧,最後當表示式掃描完後,棧裡的就是結果。
計算功能由double Operation(queue<string> q)
實現,同時它還會呼叫double Calculate(double n1, double n2, char c)
。
三 儲存到檔案
程式執行結果包括單純的中綴表示式和含結果的中綴表示式,分別儲存到不同的檔案。兩檔案分別如下:
完整程式碼
/*
構建之法第一章習題一,實現自動生成四則運算的算式並判斷使用者計算的正誤。
計劃分三步走:
1.自動生成算式
2.輸入算式轉換為逆波蘭式
3.計算算式結果
*/
#include<iostream>
#include<string>
#include<sstream>
#include<stack>
#include<queue>
#include<map>
#include<fstream>
using namespace std;
//將中綴表示式轉換為逆波蘭式
queue<string> ConvertToRpn(string s,map<string,int>p,map<char,int>p_char)
{
int length = s.length();
string temp_s="";
string temp_for_push;
stack<string>sk1;
queue<string>sk2;
sk1.push("#");
for (int i = 0; i < length;)
{
if (isdigit(s[i]))
{//判斷字元是否是0~9的數字
while (isdigit(s[i]) || s[i] == '.')
{
temp_s = temp_s + s[i];
i++;
}
sk2.push(temp_s);
temp_s.clear();
}
else
{
if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/'||s[i]=='^')
{
if (p_char[s[i]] >p[sk1.top()])
{
temp_for_push.clear();
temp_for_push = temp_for_push + s[i];
sk1.push(temp_for_push);
i++;
}
else
{
while (p_char[s[i]] <= p[sk1.top()])
{
sk2.push(sk1.top());
sk1.pop();
}
temp_for_push.clear();
temp_for_push = temp_for_push + s[i];
sk1.push(temp_for_push);
i++;
}
}
else if (s[i] == '(')
{
temp_for_push.clear();
temp_for_push = temp_for_push + s[i];
sk1.push(temp_for_push);
i++;
}
else if(s[i]==')')
{
while (sk1.top() != "(")
{
sk2.push(sk1.top());
sk1.pop();
}
sk1.pop();
i++;
}
}
if (i == length)
{
while (sk1.size() != 1)
{
sk2.push(sk1.top());
sk1.pop();
}
}
}
return sk2;
}
//生成隨機小數
double GeneratNumber()
{
double number;
int temp;
number = ((double)rand()) / ((double)(rand()/50));
temp = number * 10;
number = ((double)temp) / 10;
number = number - (int)number + (int)number % 49;
return number;
}
//生成隨機整數
int GenerateInt()
{
double int_number;
int_number = rand() % 49;
return int_number;
}
//計算逆波蘭式中簡單表示式
double Calculate(double n1, double n2, char c){
double result = 0;
if (c == '+'){
result = n1 + n2;
}
else if (c == '-'){
result = n2 - n1;
}
else if (c == '*'){
result = n1*n2;
}
else if (c == '/'){
result = n2 / n1;
}
return result;
}
//計算逆波蘭式
double Operation(queue<string> q)
{
stack<double> temp_for_digit;
char temp_for_char;
double temp_for_push = 0;
double num1, num2;
double temp_result = 0;
int length = q.size();
stringstream ss;
while (q.size() != 0)
{
if (isdigit(q.front()[0]))
{
ss << q.front();
ss >> temp_for_push;
temp_for_digit.push(temp_for_push);
q.pop();
ss.clear();
}
else
{
temp_for_char = q.front()[0];
q.pop();
num1 = temp_for_digit.top();
temp_for_digit.pop();
num2 = temp_for_digit.top();
temp_for_digit.pop();
temp_result = Calculate(num1, num2, temp_for_char);
temp_for_digit.push(temp_result);
}
}
return temp_result;
}
//生成隨機運算子
char GenerateOperator()
{
char result;
int which = rand() % 6;
if (which == 0 || which == 4)
{
result = '+';
}
else if (which == 1 || which == 5)
{
result = '-';
}
else if (which == 2)
{
result = '*';
}
else if (which == 3)
{
result = '/';
}
return result;
}
//生成左括號
int GenerateLeftBracket()
{
int result = 0;
int whether_bracket = rand() % 7;
if (whether_bracket ==1)
{
result = 1;
}
return result;
}
//生成右括號
int GenerateRightBracket()
{
int result = 0;
int whether_bracket = rand() % 7;
if (whether_bracket <= 5)
{
result = 1;
}
return result;
}
//生成表示式
string GenerateExpression()
{
string expression = "";
string temp_string;
int count_right_bracket = 0;
int length = 3;
int location_for_last_bracket = 0;
length += 2*(rand() % 15);
stringstream ss;
double temp_num;
int whether_int = 0;
int whether_bracket = 0;
for (int i = 0; i < length; i++)
{
whether_int = rand() % 5;
if (i % 2 == 0)
{
if (whether_int <= 3)
{//80%生成整數
temp_num = GenerateInt();
}
else
{
temp_num = GeneratNumber();
}
ss << temp_num;
ss >> temp_string;
expression += temp_string;
ss.clear();
if (count_right_bracket&&i>=location_for_last_bracket+3)
{
if (GenerateRightBracket())
{
count_right_bracket -= 1;
expression += ')';
}
}
}
else
{
expression += GenerateOperator();
whether_bracket= GenerateLeftBracket();
if (whether_bracket == 1)
{
expression += '(';
count_right_bracket += whether_bracket;
location_for_last_bracket = i;
}
}
}
while ((count_right_bracket--) != 0)
{
expression += ')';
}
return expression;
}
int main()
{
map<string, int> priorites;
priorites["+"] = 1;
priorites["-"] = 1;
priorites["*"] = 2;
priorites["/"] = 2;
priorites["^"] = 3;
map<char, int> priorites_char;
priorites_char['+'] = 1;
priorites_char['-'] = 1;
priorites_char['*'] = 2;
priorites_char['/'] = 2;
priorites_char['^'] = 3;
string expression;
queue<string> RPN;
double result;
int count_expression;
ofstream just_expression, answer;
just_expression.open("expression.txt");
answer.open("answer.txt");
cout << "how many expressions do you want: " << endl;
cin >> count_expression;
for (int i = 0; i<count_expression; i++)
{
expression = GenerateExpression();
RPN = ConvertToRpn(expression,priorites,priorites_char);//得到字尾表示式
result = Operation(RPN);
just_expression << i+1 << ". " << expression << endl;
answer << i+1 << ". " << expression << " = " << result << endl;
expression.clear();
RPN = queue<string>();//清空當前佇列
}
just_expression.close();
answer.close();
cout << "finished" << endl;
system("pause");
return 0;
}