首页 > 代码库 > 第一周作业——小学四则运算题

第一周作业——小学四则运算题

作业要求:

  写一个能自动生成小学四则运算题目的命令行 “软件”, 分别满足下面的各种需求,这些需求都可以用命令行参数的形式来指定:

    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),再讲分数转化为字符串,随机生成运算符与随机决定是否括号,再去之前生成的算式拼接。

  对于算式的结果计算,运用典型的中缀表达式转后缀的算法,定义一个符号栈一个分数栈进行计算。

  每次生成一个算式并要求使用者给出自己的答案,判断正误,记录结果。

 

已经实现功能:

  1. 随机生成整数或者分数算式,整数算式结果为整数,分数算式结果为真分数
  2. 真分数的四则运算,结果为真分数
  3. 支持括号
  4. 支持判断正误,给出准确率

 

代码:

  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 }
View Code

 

使用说明:

  每次选择算式类型:1.整数 2.小数(还未实现完整)3.分数。再输入题目数量。

  运算数与运算符之间用空格隔开,如:“1/2 / 2“”表示分数1/2除以2,而“1 / 2 / 2”表示1除以2再除以2)

 

运行截图:

  技术分享

  技术分享

 

后期优化计划:

  1. 已经完成小数的栈与表达式的计算部分的代码,后续抽空完成表达式生成的部分。(不过小学生还不会小数吧…)
  2. 运用模板来简化代码(三个栈,两个计算),减少代码量
  3. 支持混合运算。
  4. 支持用户输入运算的范围与算符数量。

 

暂时无法解决的问题(博主实在弱鸡...请求助教帮助..):

  1. 程序大多时候能正常运行,但是有时候会出错(针对于同样的输入信息有时候会出粗有时候不会,如下面选择整数,产生2道题目)。产生的题目数不够但自动结束,且没有报错信息。。

   技术分享

    (错误的)

   技术分享

    (正确的)

  2.单步调试的时候,每次在计算函数calculate1(),最后return时,会报下面错误:

    技术分享

 

第一周作业——小学四则运算题