四则运算3
设计思路:
程序包含两部分,一部分是算式的生成,一部分是栈的使用用来判断和计算结果;
算式生成,用的是调用子函数,因为每一个年级的出题要求不同所以对出题的范围加了条件限制;程序的结构框架大致为:
程序开始将字符串数组宏定义,出题的数量和选择打印的方式都进行宏定义;
For( )
{
For( )
{
a> 产生左括号;(用switch…..case语句来判断;)
b> 产生数字:(其中,可以有分数小数和整数的产生)
其中不同年级选择的范围不同;
c>产生右括号;(右括号的产生是用左括号的数量来限制的)
d>产生运算符;运算符在输出最后一位数字之后就不会执行运算符产生的程序;)
}
}
栈程序中:
将算式生成的string类型的数组,转化为char类型的,读入到栈中,然后利用字符串优先级的判断,计算函数,我们的程序中不能出现负数所以在输出结果时加了结果判断;
//组成员:禹慧慧 吕兰兰 //四则运算,在前面的基础上实现判断正误 2016.3.19 //我们的结果是如果选择dos界面,可以在界面上实现输入结果、判断正误与给出答案;如果选择txt,则打印出一份题目和一份答案 //没有控制余数,都算成了小数 #include<iostream> #include<ctime> #include<cmath> #include<sstream> #include<string> #include<fstream> #define MAX 1000 using namespace std; int N; int way; string str[1000]; ofstream outfile("questions.txt"); ofstream outfile_1("answers.txt"); class Input { public: Input() { for( int i = 0;i < MAX;i++ ) Str_input[i] = '\0'; } char Str_input[MAX]; void inStr(string str11) { strcpy(Str_input,str11.c_str()); } }; /*输出模块*/ class Output { public: Output() { result = 0; } void getRes( double res ) { result = res; } void printRes(double &num_an) { num_an=result; } private: double result; }; /*计算用的存储结构*/ template <class Type> class STACK{ private: Type base[MAX]; int Size; public: STACK() { Size=0; }; void push(Type a) { base[Size]=a; Size++; } Type pop() { return base[--Size]; } int size() {return Size;} }; /*计算的模块*/ class jisuan { public: bool shuhanshu(char); bool fuhanshu(char); int jckh(char); bool jcxsd(char *); int pdyxj(char); double ToData(char*); double Call(double,double,char); int ppkh(char* buffer,int pos); void Opr( STACK<char>&, STACK<double>&, int& ); double Calculate(char*, double& ); }; bool jisuan::shuhanshu(char ch) { return ((ch>='0'&&ch<='9')||ch=='.')?true:false; } bool jisuan::fuhanshu(char ch) { return (ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='#')?true:false; } int jisuan::jckh(char ch) { if(ch=='(') return 1; if(ch==')') return -1; return 0; } bool jisuan::jcxsd(char *ch) { int a=0; for(int i=0;i<strlen(ch);i++) if(ch[i]=='.') a++; if(a>1) return false; return true; } int jisuan::pdyxj(char ch) //符号的优先极别 { switch(ch) { case '+': return 0; case '-': return 0; case '*': return 1; case '/': return 1; case '#': return 0; default: return -1; } } double jisuan::ToData(char* ch) //将数字转化为数值 { int i,j,sumn=0; double sum=0.0; if(!jcxsd(ch)) return 0.0; for(i=0;i<strlen(ch);i++) { if(ch[i]!='.') sumn=sumn*10+(ch[i]-'0'); else break; } if(i<strlen(ch)) for(j=i+1;j<strlen(ch);j++) sum=sum*10+(ch[j]-'0'); sum /= pow(10.0,(double)(strlen(ch)-1-i)); return (sum+sumn); } double jisuan::Call(double sum,double data,char ch) { double ans=0.0; switch(ch) { case '+': ans=sum+data; break; case '-': ans=sum-data; break; case '*': ans=sum*data; break; case '/': if( data != 0.0 ) ans=sum/data; else { cout<<"程序出现除0错误,终止!\n"; system("pause"); exit(1); } break; case '#': return 0; default:ans=0.0; break; } return ans; } int jisuan::ppkh(char* buffer,int pos) //利用栈找到匹配的括号 { STACK<char> Temp; int i; for(i=pos;i<strlen(buffer);i++) { if(jckh(buffer[i])==1) Temp.push('0'); if(jckh(buffer[i])==-1) { Temp.pop(); if(Temp.size()==0) return i; } } return -1; } void jisuan::Opr(STACK<char>& symbol,STACK<double>& data,int& mark) { double sum; while(symbol.size()!=0) { char tem=symbol.pop(); int temp=pdyxj(tem); symbol.push(tem); if(temp<mark) break; else{ sum=Call(data.pop(),data.pop(),symbol.pop()); data.push(sum); } } } double jisuan::Calculate(char* buffer,double& sum) //字符串读入和各个函数调配 { STACK<double> data; STACK<char> symbol; double ans; char temp[MAX]; int ct=0,mark=0,tp=0; data.push(sum); while(ct<=strlen(buffer)) { if(shuhanshu(buffer[ct])) //如果是数字或小数点 { while( ct < strlen(buffer) && shuhanshu(buffer[ct]) ) temp[tp++]=buffer[ct++]; temp[tp]='\0'; tp=0; //读到非数字也非小数为止 ans=ToData(temp); //把读到的字符串转化为数 data.push(ans); if(ct==strlen(buffer)) //已经独到字符串末尾 { mark=0; Opr(symbol,data,mark); sum=data.pop(); return sum; } else{ int mark=pdyxj(buffer[ct]); Opr(symbol,data,mark); //计算 } } else if(fuhanshu(buffer[ct])) //如果是运算符 symbol.push(buffer[ct++]); //运算符入symbol栈 else { char BF[100];int k=0; //如果都不是,则只能是括号 while( jckh( buffer[ct] ) != 1 && ct <= strlen(buffer) ) BF[k++] = buffer[ct++]; BF[k]='\0'; if(jckh(buffer[ct])==1) //一旦读到左括号,寻找它匹配的右括号 { int i,j; char Temp[100]; for(i=ct+1,j=0;i<ppkh(buffer,ct);i++,j++) Temp[j]=buffer[i]; //把这对括号中的字符串存入Temp Temp[j]='\0'; data.push(Calculate(Temp,sum)); ct+=(strlen(Temp)+1); if(ct+1==strlen(buffer)) { mark=0; Opr(symbol,data,mark); sum=data.pop(); return sum; } else { mark=pdyxj(buffer[ct+1]); //不是的话继续计算 Opr(symbol,data,mark); } ct++; //读入下一个字符 } } } return 0.; } int Expression(int grade,int N) { Input in; jisuan cl; Output out; double sum=0.0; double result; double answer; cout.precision(5); int random_a,random_b,random_c,random_e,random_f,random_g; int max,min;//整数 int random_d; double random_h; //根据年级的不同选择每道题目的数的数量 if(grade==2) { random_a=rand()%2+2; max=100; min=1; } if(grade==3) { random_a=rand()%3+2; max=500; min=1; } if(grade==4) { random_a=rand()%3+2; max=1000; min=1; } if(grade==5) { random_a=rand()%3+2; max=10000; min=1; } if(grade==6) { random_a=rand()%3+2; max=10000; min=1; } for(int j=0;j<N;j++) { int flag=0; int count_p=0,count_q=0;//计算括号的数量 for(int i=0;i<random_a;i++) { if(grade==2||grade==3||grade==4) { random_b=1;//只有整数计算 } if(grade==5||grade==6) { random_b=rand()%3+0; } char str1[100]; //左括号的产生 if(random_a>2&&i<(random_a-1)) { random_d=rand()%4+0; switch(random_d)//控制括号的产生 { case 0:flag=0;break; case 1:if(i!=(random_a-1)&&i<(random_a-2)){str[j]+='(';flag=1;count_q+=1;}break; case 2:flag=0;break; case 3:if(i!=(random_a-1)&&i<(random_a-2)){str[j]+='(';flag=1;count_q+=1;}break; } } //random_b=rand()%3+0;//控制数字类型 //数字的产生 switch(random_b) { case 0: { random_h=(rand()%100)/100.0;//小数 random_e=rand()%10+0; random_h+=random_e; stringstream ss; ss<<random_h; str[j]+=ss.str(); } break; case 1: { random_c=rand()%(max-min+1)+min;//整数 itoa(random_c,str1,10); str[j]+=str1; } break; case 2: {//分数 do{ random_f=rand()%20+1; random_g=rand()%10+1; }while(random_g==random_f); int number=1; int m; if(random_g>random_f) { m=random_f; } else { m=random_g;} for(int k=2;k<m+1;k++) { if((random_g%k==0)&&(random_f%k==0)) { number=k; } } random_f=random_f/number; random_g=random_g/number; str[j]+='('; if(random_g==1) { int n=0; n=random_g; random_g=random_f; random_f=n; } itoa(random_f,str1,10); str[j]+=str1; str[j]+='/'; itoa(random_g,str1,10); str[j]+=str1; str[j]+=')'; }break; } //右括号的产生 if((flag!=1)&&(count_p!=count_q)) { str[j]+=')'; count_p+=1; } if(i==(random_a-1)) { if(count_p<count_q) { for(int k=0;k<(count_q-count_p);k++) str[j]+=')'; } } if(i!=(random_a-1)) { random_b=rand()%4+0; switch(random_b) { case 0:{str[j]+='+';}break; case 1:{str[j]+='-';}break; case 2:{str[j]+='*';}break; case 3:{str[j]+='/';}break; } } } in.inStr(str[j]); //输入模块 out.getRes( cl.Calculate(in.Str_input,sum) ); //计算模块 out.printRes(result); if (result<0) { j--; } else { if(way==1) { cout<<str[j]<<"="<<endl; cout<<"请输入答案(6位有效数字):"; cin>>answer; if (answer==result) { cout<<"回答正确!"<<endl; } else { cout<<"回答错误!"<<endl; cout<<"正确结果为:"<<result<<endl; } } else { outfile<<str[j]<<"="; outfile<<endl; outfile_1<<"正确结果为:"<<result; outfile_1<<endl; } } } return 0; } int main() { int grade; srand(time(0)); cout<<"********************************************************************************"<<endl; cout<<"********************************************************************************"<<endl; cout<<"***************************欢迎使用小学四则运算出题系统*************************"<<endl; cout<<"********************************************************************************"<<endl; cout<<"*******作者:石家庄铁道大学 信1301-2 禹慧慧 吕兰兰 2016.3.19 *******"<<endl; cout<<"********************************************************************************"<<endl; cout<<"请选择打印方式:(0-TXT,1-DOS):"; cin>>way; cout<<"********************************请选择年级**************************************"<<endl; cout<<" 2年级 "<<endl; cout<<" 3年级 "<<endl; cout<<" 4年级 "<<endl; cout<<" 5年级 "<<endl; cout<<" 6年级 "<<endl; cin>>grade; cout<<"请输入题目数量:"; cin>>N; if(grade==2) { Expression(grade,N); } if(grade==3) { Expression(grade,N); } if(grade==4) { Expression(grade,N); } if(grade==5) { Expression(grade,N); } if(grade==6) { Expression(grade,N); } outfile.close(); outfile_1.close(); }
项目计划日志(单位:h)
听课 |
编写程序 |
阅读相关书籍 |
网上查找资料 |
日总计 |
|
周一 |
2 |
0 |
1 |
0 |
3 |
周二 |
0 |
3 |
|
0.5 |
3.5 |
周三 |
0 |
3 |
1 |
0 |
4 |
周四 |
2 |
6 |
|
1 |
9 |
周五 |
0 |
4 |
0 |
2 |
6 |
周六 |
0 |
3 |
|
1 |
4 |
周日 |
|
|
|
|
|
周总计 |
4 |
19 |
2 |
4.5 |
29.5 |
时间记录日志:(单位:min):
日期 |
开始时间 |
结束时间 |
中断时间 |
净时间 |
活动 |
备注 |
星期一 |
14:00 |
15:50 |
10 |
100 |
听课 |
软件工程 |
|
20:00 |
21:00 |
0 |
60 |
看书 |
构建之法 |
星期二 |
19:00 |
19:30 |
0 |
30 |
网上查找资料 |
|
|
20:00 |
23:00 |
0 |
180 |
编程 |
结对编程 |
星期三 |
15:00 |
22:00 |
180 |
240 |
编程和上网查找资料并且调试程序 |
结对编程 |
星期四 |
14:00 |
15:50 |
10 |
100 |
听课 |
软件工程 |
|
16:00 |
23:00 |
60 |
360 |
编程 |
结对编程 |
星期五 |
16:00 |
21:00 |
30 |
270 |
编程上网查找资料 |
结对编程
|
星期六 |
19:00 |
22:00 |
0 |
180 |
编程和写博客 |
结对编程 |
缺陷记录日志:
日期 |
编号 |
类型 |
引入阶段 |
排除阶段 |
修复时间 |
修复缺陷 |
3/17 |
1 |
20 |
编码 |
调试 |
20:00 |
括号输出错误,运算不正确 |
3/18 |
2 |
20 |
编码 |
调试 |
19:00-21:00 |
对栈的编写和运算结果 |
3/19 |
3 |
20 |
编码 |
调试 |
20:00-22:00 |
括号的丢失和语法的错误。 |
组成员吕兰兰网址:http://www.cnblogs.com/lvlan/