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


    作业要求:

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

        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=='
    '){
     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] = '';
    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     else
    220         {
    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     else
    268         {
    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     else
    315         {
    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]='';
    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]='';
    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: 
    1.integer
    2.decimals
    3.fraction
    ";
    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时,会报下面错误:

        

  • 相关阅读:
    BZOJ 1050 旅行
    BZOJ 1040 骑士
    BZOJ 1038 瞭望塔
    BZOJ 1037 生日聚会
    BZOJ 1823 满汉全席
    BZOJ 3091 城市旅行
    CF702E Analysis of Pathes in Functional Graph
    Luogu 2154 [SDOI2009]虔诚的墓主人
    Luogu 1268 树的重量
    Luogu 4867 Gty的二逼妹子序列
  • 原文地址:https://www.cnblogs.com/Oranswj/p/5910276.html
Copyright © 2020-2023  润新知