首页 > 代码库 > 第一周作业——小学四则运算题
第一周作业——小学四则运算题
作业要求:
写一个能自动生成小学四则运算题目的命令行 “软件”, 分别满足下面的各种需求,这些需求都可以用命令行参数的形式来指定:
a) 支持整数、真分数的四则运算。例如: 1/6 + 1/8 = 7/24
b) 让程序能接受用户输入答案,并判定对错,最后给出总共 对/错 的数量。
c) 逐步扩展功能和可以支持的表达式类型,最后希望能支持下面类型的题目(最多 10 个运算符,括号的数量不限制)
25 - 3 * 4 - 2 / 2 + 89 = ?
1/2 + 1/3 - 1/4 = ?
( 5 - 4 ) * ( 3 +28 ) =?
设计思路:
定义分数类,重载四则运算符+-*/、赋值符号=、逻辑运算符==和输出输出流。
对于整数,看做真分数的一种特例即可。
对于算式的生成,先随机生成运算符的数量(题目要求10个,但是针对于小学生而言..十个还是有点多),采用rand() 随机生成分子分母并化简(整数分子为1),再讲分数转化为字符串,随机生成运算符与随机决定是否括号,再去之前生成的算式拼接。
对于算式的结果计算,运用典型的中缀表达式转后缀的算法,定义一个符号栈一个分数栈进行计算。
每次生成一个算式并要求使用者给出自己的答案,判断正误,记录结果。
已经实现功能:
- 随机生成整数或者分数算式,整数算式结果为整数,分数算式结果为真分数
- 真分数的四则运算,结果为真分数
- 支持括号
- 支持判断正误,给出准确率
代码:
GitHub: https://github.com/chynphh/Elementary-arithmetic
1 #include <iostream> 2 #include <string> 3 #include <string.h> 4 #include <math.h> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <ctime> 8 using namespace std; 9 10 #define OK 1 11 #define ERROR 0 12 #define TRUE 1 13 #define FALSE 0 14 #define MAX 1000 15 #define ADD 100 16 typedef int Status; 17 18 19 // 整数转字符串 20 string itoa_i(int x){ 21 char str[20]; 22 itoa(x, str, 10); 23 return str; 24 25 } 26 27 //求最大公约数 28 int gcd(int m,int n){ 29 if(m%n==0) 30 return n; 31 else 32 return gcd(n,m%n); 33 } 34 35 //分数类 36 class Fraction{ 37 public: 38 Fraction(int x1=0,int z2=1);////构造函数 39 void huajian();//分数化简 40 Fraction operator + (Fraction f2);//运算符重载 + 41 Fraction operator - (Fraction f2);//运算符重载 - 42 Fraction operator * (Fraction f2);//运算符重载 * 43 Fraction operator / (Fraction f2);//运算符重载 / 44 Fraction& operator= (const Fraction& frac){ 45 x = frac.x; 46 z = frac.z; 47 return *this; 48 } 49 bool operator==(const Fraction &c); 50 51 friend void operator >>(istream& in,Fraction &f);//输入流重载 52 friend void operator <<(ostream& out,Fraction &f);//输出流重载 53 54 55 int x;//分子 56 int z;//分母 57 }; 58 59 //输出流重载 60 void operator<<(ostream& out,Fraction &f){ 61 if(f.x==0) out<<" 0"; 62 else if(f.z==1) out<<f.x; 63 else if(f.z==-1) out<<-1*f.z; 64 else{ 65 if(f.x*f.z>0) 66 out<<abs(f.x)<<‘/‘<<abs(f.z); 67 else 68 out<<-1*abs(f.x)<<‘/‘<<abs(f.z); 69 70 } 71 } 72 73 //输入流重载 74 void operator>>(istream& in,Fraction &f){ 75 char c; 76 in>>f.x; 77 in.unsetf(ios::skipws);// 78 in>>c; 79 in.setf(ios::skipws);// 80 if(c != ‘/‘){ 81 if(c==‘\n‘){ 82 f.z = 1; 83 } 84 else{ 85 in>>f.z; 86 throw c; 87 } 88 } 89 else{ 90 in>>f.z; 91 if(f.z == 0) 92 throw f.z; 93 } 94 } 95 96 //逻辑运算符==重载 97 bool Fraction::operator==(const Fraction &c){ 98 if (x == c.x && z == c.z) return true; 99 return false;100 }101 102 //分数转字符串103 string itoa_f(Fraction a){104 string s = "";105 if(a.z == 1) s = s + itoa_i(a.x) + "";106 else s = s + itoa_i(a.x) + "/" + itoa_i(a.z) ;107 return s;108 }109 110 //字符串转整数111 Fraction atof_f(char* a){112 Fraction f;113 int i = 0, l = 0;114 char* b;115 l = strlen(a);116 while(a[i] != ‘/‘ && i < l)i++;117 if(i < l) {118 b = a + i + 1;119 f.z = atoi(b);120 }121 else {122 f.z = 1;123 }124 125 a[i] = ‘\0‘;126 f.x = atoi(a);127 128 return f;129 }130 131 //构造函数132 Fraction::Fraction(int x1,int z2){133 x = x1;134 z = z2;135 }136 137 //分数化简138 void Fraction::huajian(){139 int gc;140 gc=gcd(abs(x),abs(z));141 x/=gc;142 z/=gc;143 }144 145 //运算符重载 +146 Fraction Fraction::operator +(Fraction f2){147 int a, b;148 Fraction ff;149 a=x*f2.z+z*f2.x;150 b=z*f2.z;151 ff.x=a;152 ff.z=b;153 ff.huajian();154 return ff;155 }156 157 //运算符重载 -158 Fraction Fraction::operator -(Fraction f2){159 int a, b;160 Fraction ff;161 a=x*f2.z-z*f2.x;162 b=z*f2.z;163 ff.x=a;164 ff.z=b;165 ff.huajian();166 return ff;167 }168 169 //运算符重载 *170 Fraction Fraction::operator *(Fraction f2){171 int a, b;172 Fraction ff;173 a=x*f2.x;174 b=z*f2.z;175 ff.x=a;176 ff.z=b;177 ff.huajian();178 return ff;179 }180 181 //运算符重载 /182 Fraction Fraction::operator /(Fraction f2){183 if(f2.x==0){184 throw f2.x ;185 }186 else{187 int a, b;188 Fraction ff;189 a=x*f2.z;190 b=z*f2.x;191 ff.x=a;192 ff.z=b;193 ff.huajian();194 return ff;195 }196 }197 198 199 200 //定义字符栈201 typedef struct{202 char *top; //指向栈顶203 char *base; //指向栈底(动态分配内存的首地址)204 int stacksize; //可用存储空间205 }stack_char;206 207 //构造空栈208 Status InitStack(stack_char &s){209 s.base=(char *)malloc(MAX * sizeof(char));210 if(!s.base)exit(OVERFLOW);//储存分配失败211 s.top=s.base;212 s.stacksize=MAX;213 return OK;214 }215 216 //获取栈顶元素217 char GetTop(stack_char s,char &e){218 if (s.top==s.base)return false;219 else220 {221 e = *(s.top-1);222 return OK;223 }224 }225 226 //入栈227 Status Push(stack_char &s, char e) {228 if(s.top-s.base>=MAX){229 s.base = (char *)realloc(s.base,(s.stacksize + ADD)*sizeof(char));230 if(!s.base)exit(OVERFLOW);231 s.top=s.base+s.stacksize;232 s.stacksize =s.stacksize + ADD;233 }234 *s.top=e;235 s.top++;236 return OK;237 }238 239 //出栈240 Status Pop(stack_char &s,char &e){241 if(s.top==s.base)return ERROR;242 s.top--;243 e=*s.top;244 return OK;245 }246 247 248 //定义小数栈249 typedef struct{250 double *top; //指向栈顶251 double *base; //指向栈底(动态分配内存的首地址)252 int stacksize; //可用存储空间253 }stack_double;254 255 //构造空栈256 Status InitStack(stack_double &s){257 s.base=(double *)malloc(MAX * sizeof(double));258 if(!s.base)exit(OVERFLOW);//储存分配失败259 s.top=s.base;260 s.stacksize=MAX;261 return OK;262 }263 264 //获取栈顶元素265 Status GetTop(stack_double s,double &e){266 if (s.top==s.base)return false;267 else268 {269 e = *(s.top-1);270 return OK;271 }272 }273 274 //入栈275 Status Push(stack_double &s, double e) {276 if(s.top-s.base>=MAX){277 s.base = (double *)realloc(s.base,(s.stacksize + ADD)*sizeof(double));278 if(!s.base)exit(OVERFLOW);279 s.top=s.base+s.stacksize;280 s.stacksize =s.stacksize + ADD;281 }282 *s.top=e;283 s.top++;284 return OK;285 }286 287 //出栈288 Status Pop(stack_double &s,double &e){289 if(s.top==s.base)return ERROR;290 s.top--;291 e=*s.top;292 return OK;293 }294 295 //定义分数栈296 typedef struct{297 Fraction *top; //指向栈顶298 Fraction *base; //指向栈底(动态分配内存的首地址)299 int stacksize; //可用存储空间300 }stack_Fraction;301 302 //构造空栈303 Status InitStack(stack_Fraction &s){304 s.base=(Fraction *)malloc(MAX * sizeof(Fraction));305 if(!s.base)exit(OVERFLOW);//储存分配失败306 s.top=s.base;307 s.stacksize=MAX;308 return OK;309 }310 311 //获取栈顶元素312 Status GetTop(stack_Fraction s,Fraction &e){313 if (s.top==s.base)return false;314 else315 {316 e = *(s.top-1);317 return OK;318 }319 }320 321 //入栈322 Status Push(stack_Fraction &s, Fraction e) {323 if(s.top-s.base>=MAX){324 s.base = (Fraction *)realloc(s.base,(s.stacksize + ADD)*sizeof(Fraction));325 if(!s.base)exit(OVERFLOW);326 s.top=s.base+s.stacksize;327 s.stacksize =s.stacksize + ADD;328 }329 *s.top = e;330 s.top++;331 return OK;332 }333 334 //出栈335 Status Pop(stack_Fraction &s,Fraction &e){336 if(s.top==s.base)return ERROR;337 s.top--;338 e = *s.top;339 return OK;340 }341 342 char op[7]={ ‘+‘,‘-‘,‘*‘,‘/‘,‘(‘,‘)‘, ‘#‘};343 //优先权集合344 char priority[7][7]=345 { {‘>‘,‘>‘,‘<‘,‘<‘,‘<‘,‘>‘,‘>‘},346 {‘>‘,‘>‘,‘<‘,‘<‘,‘<‘,‘>‘,‘>‘},347 {‘>‘,‘>‘,‘>‘,‘>‘,‘<‘,‘>‘,‘>‘},348 {‘>‘,‘>‘,‘>‘,‘>‘,‘<‘,‘>‘,‘>‘},349 {‘<‘,‘<‘,‘<‘,‘<‘,‘<‘,‘=‘,‘@‘},350 {‘>‘,‘>‘,‘>‘,‘>‘,‘@‘,‘>‘,‘>‘},351 {‘<‘,‘<‘,‘<‘,‘<‘,‘<‘,‘@‘,‘=‘} };352 353 char Precede(char a,char b){354 int i,j;355 for(int k=0;k<7;k++){356 if(op[k]==a)i=k;357 if(op[k]==b)j=k;358 }359 return priority[i][j];360 }361 362 bool In(char e,char *a){363 int l;364 l=strlen(a);365 bool temp=false;366 for(int i=0;i<l;i++)367 {368 if(a[i]==e)temp=true;369 }370 return temp;371 }372 373 template<typename T>374 T Operate(T x,char c,T y)375 {376 switch(c)377 {378 case‘+‘:return x + y;break;379 case‘-‘:return x - y;break;380 case‘*‘:return x * y;break;381 case‘/‘:return x / y;break;382 }383 }384 385 //分数计算386 Fraction calculate1(string str){387 388 stack_char optr;389 stack_Fraction opnd_f;390 391 InitStack(optr);392 InitStack(opnd_f);393 394 int l;395 l = str.size();396 str[l] = ‘ ‘;397 l++;398 str[l] = ‘#‘;399 l++;400 Push(optr,‘#‘);401 402 int i=0;403 char t;404 GetTop(optr,t);405 while((str[i]!=‘#‘|| t!=‘#‘) && i < l){406 if((str[i]==‘(‘ && str[i+1]!=‘-‘) || (In(str[i],op)==1 && str[i]!=‘(‘)){407 char x,theta;408 Fraction a,b;409 GetTop(optr,t);410 switch(Precede(t,str[i])){411 case ‘<‘:412 Push(optr,str[i]);413 i++;414 break;415 case ‘=‘:416 Pop(optr,x);417 i++;418 break;419 case ‘>‘:420 Pop(optr,theta);421 Pop(opnd_f,b);422 Pop(opnd_f,a);423 Push(opnd_f,Operate(a,theta,b)) ;424 break;425 }426 }427 else{428 int k=0;429 char temp[20];430 Fraction x;431 while (str[i+k+1]!=‘ ‘){432 k++;433 }434 strncpy(temp,&str[i],k+1);435 temp[k+1]=‘\0‘;436 x = atof_f(temp);437 Push(opnd_f,x);438 i=i+k+1;439 }440 while(str[i]==‘ ‘)i++;441 GetTop(optr,t);442 }443 444 Fraction answer;445 GetTop(opnd_f,answer);446 // cout << answer;447 // cout << endl;448 return answer;449 }450 451 //小数计算452 double calculate2(string str){453 454 stack_char optr;455 stack_double opnd_d;456 InitStack(optr);457 InitStack(opnd_d);458 459 460 char l;461 l = str.size();462 str[l]=‘#‘;463 l++;464 Push(optr,‘#‘);465 466 int i=0;467 char t;468 GetTop(optr,t);469 470 while(str[i]!=‘#‘|| t!=‘#‘)471 {472 if( In(str[i],op)==1 && str[i]!=‘(‘ )473 {474 char x,theta;475 double a,b;476 GetTop(optr,t);477 switch(Precede(t,str[i])){478 case ‘<‘:479 Push(optr,str[i]);480 i++;481 break;482 case ‘=‘:483 Pop(optr,x);484 i++;485 break;486 case ‘>‘:487 Pop(optr,theta);488 Pop(opnd_d,b);489 Pop(opnd_d,a);490 Push(opnd_d,Operate(a,theta,b)) ;491 break;492 }493 }494 else{495 int k=0;496 char temp[20];497 double x;498 while((!In(str[i+k+1],op)) || (In(str[i+k+1],op) && str[i+k+2]!=‘ ‘)){499 k++;500 }501 strncpy(temp,&str[i],k+1);502 temp[k+1]=‘\0‘;503 x = atof(temp);504 Push(opnd_d,x);505 i=i+k+1;506 while(str[i]==‘ ‘)i++;507 }508 GetTop(optr,t);509 }510 511 double answer;512 GetTop(opnd_d,answer);513 514 return answer;515 }516 517 char opp(int op){518 switch(op){519 case 0: return ‘+‘;520 case 1: return ‘-‘;521 case 2: return ‘*‘;522 case 3: return ‘/‘;523 }524 }525 526 //随机生成算式527 string Create(int type){528 int num_op = 0;529 string exp = "";530 num_op = rand()%10 + 1;//符号个数531 Fraction a;532 int b, c, d; // b是符号,c是左右部,d是有无括号533 534 switch(type){535 case 1:536 a.x = rand()%100 + 1;537 a.z = 1;538 a.huajian();539 exp = exp + itoa_f(a);540 while(num_op--){541 b = rand()%4;542 d = rand()%3;543 c = rand()%2;544 if(b == 3) a.x = rand()%5 + 1; //除法设置除数较小545 else if (b == 2) a.x = rand()%20 +1; // 乘法设置乘数相对较小546 else a.x = rand()%100 +1;547 a.huajian();548 if(c){ //当做左部549 exp = exp + ‘ ‘ + opp(b) + ‘ ‘ + itoa_f(a);550 }551 else{ // 当做右部552 exp = itoa_f(a) + ‘ ‘ + opp(b) + ‘ ‘ + exp;553 }554 if(b == 0 && num_op > 0){555 exp = "( " + exp + " )";556 }557 }558 break;559 case 2 :560 break;561 case 3:562 a.x = rand()%30 + 1;563 a.z = rand()%10 + 1;564 a.huajian();565 exp = exp + itoa_f(a);566 while(num_op--){567 b = rand()%4;568 d = rand()%3;569 c = rand()%2;570 if(c){ //当做左部571 a.x = rand()%30 + 1;572 a.z = rand()%10 + 1;573 a.huajian();574 exp = exp + ‘ ‘ + opp(b) + ‘ ‘ + itoa_f(a);575 }576 else{ // 当做右部577 a.x = rand()%30 + 1;578 a.z = rand()%10 + 1;579 exp = itoa_f(a) + ‘ ‘ + opp(b) + ‘ ‘ + exp;580 }581 if(b == 0 && num_op > 0){582 exp = "( " + exp + " )";583 }584 }585 break;586 }587 return exp;588 }589 590 int start(int num, int type){591 int num_right = 0;592 string exp;593 Fraction std_ans_f, ans_f;594 double std_ans_d = 0.0, ans_d = 0.0;595 596 while(num--){597 exp = Create(type);598 if(type != 2){//整数 或者 真分数运算599 std_ans_f = calculate1(exp);600 if(type == 1)//整数运算保证结果为整数601 while(std_ans_f.z != 1){602 exp = Create(type);603 std_ans_f = calculate1(exp);604 }605 cout << "Q:"<< exp << " " << endl;606 cout << "your ans:" ;607 cin >> ans_f;608 cout << "the right ans:";609 cout << std_ans_f ;610 cout << endl << endl;611 612 if(std_ans_f == ans_f)num_right++;613 }614 else{//小数部分 未完善615 616 }617 exp="";618 }619 return num_right;620 }621 622 623 int main ()624 {625 srand(time(0)); //初始化随机数发生器626 627 int type = -1, num = 0, num_right = 0;628 double acc = 0.0;629 cout << "Please select the type of problem: \n1.integer\n2.decimals\n3.fraction\n";630 cin >> type;631 while(type < 1 || type > 3){632 cout << "Please select the correct type of problem" << endl;633 cin >> type;634 }635 cout << "please input the number of problems " << endl;636 cin >> num;637 num_right = start(num, type);638 acc = num_right * 1.0 / num;639 cout << "The number of question : " << num << endl;640 cout << "The number of correct answer : "<< num_right << endl;641 cout << "your accuracy is " << acc <<endl;642 return 0;643 }
使用说明:
每次选择算式类型:1.整数 2.小数(还未实现完整)3.分数。再输入题目数量。
运算数与运算符之间用空格隔开,如:“1/2 / 2“”表示分数1/2除以2,而“1 / 2 / 2”表示1除以2再除以2)
运行截图:
后期优化计划:
- 已经完成小数的栈与表达式的计算部分的代码,后续抽空完成表达式生成的部分。(不过小学生还不会小数吧…)
- 运用模板来简化代码(三个栈,两个计算),减少代码量
- 支持混合运算。
- 支持用户输入运算的范围与算符数量。
暂时无法解决的问题(博主实在弱鸡...请求助教帮助..):
- 程序大多时候能正常运行,但是有时候会出错(针对于同样的输入信息有时候会出粗有时候不会,如下面选择整数,产生2道题目)。产生的题目数不够但自动结束,且没有报错信息。。
(错误的)
(正确的)
2.单步调试的时候,每次在计算函数calculate1(),最后return时,会报下面错误:
第一周作业——小学四则运算题