结对四则运算编程(5212邓画月+5213何颖琪)

一:Github项目地址 https://github.com/vicky-3653/operation

项目负责人:邓画月 何颖琪

 

题目:实现一个自动生成小学四则运算题目的命令行程序。

说明:

自然数:0, 1, 2, …。

  • 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
  • 运算符:+, ?, ×, ÷。
  • 括号:(, )。
  • 等号:=。
  • 分隔符:空格(用于四则运算符和等号前后)。
  • 算术表达式:e = n | e1 + e2 | e1 ? e2 | e1 × e2 | e1 ÷ e2 | (e),

其中e, e1和e2为表达式,n为自然数或真分数。

  • 四则运算题目:e = ,其中e为算术表达式。

需求:

1. 使用 -n 参数控制生成题目的个数,例如Myapp.exe -n 10将生成10个题目。

2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如Myapp.exe -r 10

将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

3. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1 ? e2的子表达式,那么e1 ≥ e2

4. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数

5. 每道题目中出现的运算符个数不超过3个。

6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+33+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:

1. 四则运算题目1

2. 四则运算题目2

……

其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

7. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

1. 答案1

2. 答案2

特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

8. 程序应能支持一万道题目的生成。

9. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt

统计结果输出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)

Wrong: 5 (2, 4, 6, 8, 10)

其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

二: PSP2.1表格


PSP2.1


Personal Software Process Stages


预估耗时(分钟)


实际耗时(分钟)


Planning


计划

 180 180 

· Estimate


· 估计这个任务需要多少时间

 1950 2300

Development


开发

 120  120

· Analysis


· 需求分析 (包括学习新技术)

 600  600

· Design Spec


· 生成设计文档

 30  40

· Design Review


· 设计复审 (和同事审核设计文档)

 30  40

· Coding Standard


· 代码规范 (为目前的开发制定合适的规范)

 30  30

· Design


· 具体设计

 200  180

· Coding


· 具体编码

 400  630

· Code Review


· 代码复审

 120  200

· Test


· 测试(自我测试,修改代码,提交修改)

 180  120

Reporting


报告

 120  120

· Test Report


· 测试报告

 50  50

· Size Measurement


· 计算工作量

 40  40

· Postmortem & Process Improvement Plan


· 事后总结, 并提出过程改进计划

 30  30

合计

     2300

三:效能分析

性能分析图:

在分析设计过程中,选择先实现题目与答案文件的打印,后来发现难实现对比练习文件和答案文件,

所以选择了另外一种实现方法,让用户选择程序的运行,分别是出练习题和对答案。

四:设计实现过程和代码说明

主函数:

主函数实现了选择功能的框架,并实现了参数必须给定的要求,否则程序报错并给出帮助信息。

  1 int main()
  2 {
  3     FILE *fq;//题目的文档
  4     FILE *fa;//答案的文档
  5     int x;
  6     printf("选择序号:\n1.出题目\n2.对答案\n");
  7     scanf("%d",&x);
  8     while(x!=1 && x!=2)//选择功能
  9     {
 10     printf("重新输入功能!\n");
 11     scanf("%d",&x);
 12     if(x!=1 && x!=2)
 13     continue;
 14     }
 15     switch(x)
 16     {
 17     case 1:
 18     {
 19     if((fq=fopen("Exercises.txt","w"))==NULL){
 20     printf("Cannot open this file!\n");
 21     exit(0);
 22     }
 23     if((fa=fopen("Answers.txt","w"))==NULL){
 24     printf("Cannot open this file!\n");
 25     exit(0);
 26     }
 27     srand(time(0));
 28     int m;
 29     int n,r;
 30     printf("请输入题目个数\n");
 31     printf("Myapp.exe -n ");
 32     while(1){//该参数必须给定,否则程序报错并给出帮助信息。
 33         if(scanf("%d",&n)==1)break;
 34         else printf("请重新输入1或者其他自然数:");
 35         fflush(stdin);
 36     }
 37
 38     printf("请输入题目中数值的范围\n");
 39     printf("Myapp.exe -r ");
 40     while(1){//该参数必须给定,否则程序报错并给出帮助信息。
 41         if(scanf("%d",&r)==1)break;
 42         else printf("请重新输入1或者其他自然数:");
 43         fflush(stdin);
 44     }
 45
 46
 47     //循环出题
 48     for(int i=0;i<n;i++){
 49           m=rand()%3+1;//m=1or2or3
 50           printf("%d.",i+1);
 51           fprintf(fq,"%d.",i+1);
 52           fprintf(fa,"%d.",i+1);
 53         switch(m){
 54             case 1:{
 55                 print1(r,fq,fa);
 56                 printf("\n");
 57                 fprintf(fq,"\n");
 58                 fprintf(fa,"\n");
 59                 break;
 60             }
 61             case 2:{
 62                 print2(r,fq,fa);
 63                 printf("\n"); //打印函数2
 64                 fprintf(fq,"\n");
 65                 fprintf(fa,"\n");
 66                 break;
 67             }
 68             case 3:{
 69                 print3(r,fq,fa);//打印函数3
 70                 printf("\n");
 71                 fprintf(fq,"\n");
 72                 fprintf(fa,"\n");
 73                 break;
 74             }
 75         }
 76     }
 77     fclose(fq);
 78     fclose(fa);
 79     break;
 80 }
 81 //对答案
 82     case 2 :
 83     {FILE *ans;
 84     FILE *stu;
 85     if((ans=fopen("Answers.txt","r"))==NULL){
 86     printf("Cannot open this file!\n");
 87     exit(EXIT_FAILURE);
 88     }
 89     if((stu=fopen("Student.txt","r"))==NULL){
 90     printf("Cannot open this file!\n");
 91     exit(EXIT_FAILURE);
 92     }
 93     int r;
 94     printf("一共有多少题:");
 95     scanf("%d",&r);
 96     check(ans,stu,r);
 97
 98     break;
 99     }
100
101      return 0;
102 }
103 }

练习题文件和答案文件的打印:

练习题和答案分成了case1,2,3,分别对应两个分数的运算,两个整数的运算,一个整数一个分数的运算,通过主函数随机调用print123,达到随机生成不同运算。

运算式的生成中,分母不能为0,不能生成答案为负的式子。

我们另外调用了分数和整数的比较函数frac_fracompare,分数比较函数frac_fraccompare,分数显示函数show,去分子分母公约数函数simple。

获取随机数的函数运用到了rand()%。

void print1(int r,FILE *fq,FILE *fa){//两个都是分数的打印
   int a,b,c,d,f,g,h;
   char e; 

   a=Creat_Int(r);
   b=Creat_Int(r);
   c=Creat_Int(r);
   d=Creat_Int(r);

    while(b==0){
        b=Creat_Int(r);
        //b=rand()%r;
        break;
    }
    while(d==0){
        d=Creat_Int(r);
        //d=rand()%r;
        break;
    }

   e=getSignal();

   simple(&a,&c);
   simple(&b,&d);

   frac_fraccompare(&a,&b,&c,&d);//若a/c < b/d 调换位置 

//显示产生的算式
show(a,c,r,fq);//经常会显示分数
switch(e)
{
     case ‘+‘: {
         printf(" + ");
         fprintf(fq," %c ",e);
        break;
     }
     case ‘-‘: {
         printf(" - ");
         fprintf(fq," %c ",e);
        break;
     }
     case ‘*‘: {
         printf(" * ");
         fprintf(fq," %c ",e);
        break;
     }
     case ‘/‘:{
         printf(" / ");
         fprintf(fq," %c ",e);
        break;
     }
}
show(b,d,r,fq);
printf(" = ");
fprintf(fq," = ");

switch(e) //答案
{
    case ‘+‘:
     f=a*d+b*c;
     g=c*d;
     simple(&f,&g);
     show(f,g,r,fa);
     break;

    case ‘-‘:
     f=a*d-b*c;
     g=c*d;
     simple(&f,&g);
     show(f,g,r,fa);
     break;

     case ‘*‘:
      f=a*b;
      g=c*d;
      simple(&f,&g);
      show(f,g,r,fa);
      break;

     case ‘/‘:
      f=a*d;
      g=b*c;
      simple(&f,&g);
      show(f,g,r,fa);
     break;
}
}
void print2(int r,FILE *fq,FILE *fa){//两个都是整数的打印
    int num1,num2;
    char signal;
    signal=getSignal();

    num1=Creat_Int(r);
    num2=Creat_Int(r);

    switch(signal){
        case ‘+‘:{
            printf("%d + %d = ",num1,num2);
            fprintf(fq,"%d + %d = ",num1,num2);
            break;
        }
        case ‘-‘:{
            if(num1<num2){
                int t;
                t=num1;
                num1=num2;
                num2=t;
            }
            printf("%d - %d = ",num1,num2);
            fprintf(fq,"%d - %d = ",num1,num2);
            break;
        }
        case ‘*‘:{
            printf("%d * %d = ",num1,num2);
            fprintf(fq,"%d * %d = ",num1,num2);
            break;
        }
        case ‘/‘:{
            while(num2==0){
                num2=Creat_Int(r);
            }
            if(num1>num2){
                int t;
                t=num1;
                num1=num2;
                num2=t;
            }
            printf("%d / %d = ",num1,num2);
            fprintf(fq,"%d / %d = ",num1,num2);
            break;
        }

    }

    //计算的
    switch(signal)
{
case ‘+‘:
    int c;
    c=num1+num2;
    printf("%d",c);
    fprintf(fa,"%d",c);
    break;
case ‘-‘:
    c=num1-num2;
    printf("%d",c);
    fprintf(fa,"%d",c);
    break;
case ‘*‘:
    c=num1*num2;
    printf("%d",c);
    fprintf(fa,"%d",c);
    break;
case ‘/‘:
    c=num1/num2;
    show(num1,num2,r,fa);
    break;
}

}
void print3(int r,FILE *fq,FILE *fa){//一整一分的打印 

    int fenzi,fenmu,num1;
    char signal;
    fenzi=Creat_Int(r);
    fenmu=Creat_Int(r);
    num1=Creat_Int(r);

    signal=getSignal();

    while(fenmu==0){
                fenmu=Creat_Int(r);
            }
    if(fenzi>fenmu){
                int t;
                t=fenzi;
                fenzi=fenmu;
                fenmu=t;
            }
    simple(&fenzi,&fenmu);    

    switch(signal){
        case ‘+‘:{
        printf("%d %c ",num1,signal);
        fprintf(fq,"%d %c ",num1,signal);
        show(fenzi,fenmu,r,fq);
        printf(" = ");
        fprintf(fq," = ");
        break;
        }
        case ‘-‘:{
        while(num1==0){
            num1=Creat_Int(r);
        }
        printf("%d %c ",num1,signal);
        fprintf(fq,"%d %c ",num1,signal);
        show(fenzi,fenmu,r,fq);
        printf(" = ");
        fprintf(fq," = ");
        break;
        }
        case ‘*‘:{
        printf("%d %c ",num1,signal);
        fprintf(fq,"%d %c ",num1,signal);
        show(fenzi,fenmu,r,fq);
        printf(" = ");
        fprintf(fq," = ");
        break;
        }
        case ‘/‘:{
        while(fenzi==0){
        fenzi=Creat_Int(r);
        }
        printf("%d %c ",num1,signal);
        fprintf(fq,"%d %c ",num1,signal);
        show(fenzi,fenmu,r,fq);
        printf(" = ");
        fprintf(fq," = ");
        break;
        }
    } 

    //计算的
    switch(signal){
        int x;
        case ‘+‘:{
            x=fenmu*num1+fenzi;
            simple(&x,&fenmu);
            show(x,fenmu,r,fa);
            break;
        }
        case ‘-‘:{
            x=fenmu*num1-fenzi;
            simple(&x,&fenmu);
            show(x,fenmu,r,fa);
            break;
        }
        case ‘*‘:{
            x=fenzi*num1;
            simple(&x,&fenmu);
            show(x,fenmu,r,fa);
            break;
        }
        case ‘/‘:{
            x=fenmu*num1;
            simple(&fenzi,&x);
            show(x,fenzi,r,fa);
            break;
        }
    } 

}

随机获取符号函数和随机获取整数函数:

1 char getSignal(){//随机获取运算符函数
2     char signal[4]={‘+‘,‘-‘,‘*‘,‘/‘};
3     //srand((unsigned)time(NULL));
4     //srand(time(0));
5     return signal[rand()%4];
6 }
7 int Creat_Int(int r){//随机获取整数函数
8     return rand()%r;
9 }

约去分子分母公约数函数:

void simple(int * m,int * n){ //约去分子分母公约数 需要用指针改数字,因为返回是void
    int p;
    p=(*m+*n-abs(*m-*n))/2;//p为m,n中的小值
    for(int i=2;i<=p;i++){
    if(*m%i==0&&*n%i==0)
    {
      *m/=i;
      *n/=i;
      i=2;
    }
    }
}

分数和整数的比较函数:

int frac_intcompare(int fenzi,int fenmu,int a){//分数和整数的比较函数
    int d;
    int flag;
    d=fenmu*a;
    if((fenzi/d)>=1)flag=1;//分数(a/b)大于整数
    else flag=0;
    return flag;
}

带又的真分数转换函数:

int show(int a,int b,int r,FILE *fp){//分数转换为带又的真分数
    int c;
    while(b==0){
        b=Creat_Int(r);
        //b=rand()%r;
    }

    c=a/b;
    if(a==0) {
        printf("%d",a);
        fprintf(fp,"%d",a);
    }
    else if(a%b==0) {
        printf("%d",c);
        fprintf(fp,"%d",c);
    }
    else if(c==0) {
        simple(&a,&b);
        printf("%d/%d",a,b);
        fprintf(fp,"%d/%d",a,b);
    }
    else {
    a=a-b*c;
    simple(&a,&b);
    printf("%d‘%d/%d",c,a,b);
    fprintf(fp,"%d‘%d/%d",c,a,b);
    }
}

调换位置函数:

void frac_fraccompare(int *fenzi1,int *fenzi2,int *fenmu1,int *fenmu2){//若a/c < b/d 调换位置
    int m,n;
    int a,b;
    a=(*fenzi1) * (*fenmu2);
    b=(*fenmu1) * (*fenzi2);
    if(a<b){
        m=*fenzi1;
        *fenzi1=*fenzi2;
        *fenzi2=m;

        n=*fenmu1;
        *fenmu1=*fenmu2;
        *fenmu2=n;
    }
}
    

比较文件答案函数:

答案文件的比较,我们的思路是通过读写学生文件与原答案文件进行对比,不同的题目转换成正确和错误的数组,再通过数组形式输出right和wrong。

void check(FILE *ans,FILE *stu,int n){
    char a[n+1];
    char s[n+1];
    int right[n+1];
    int wrong[n+1];
    char *p;
    char *q;
    int num=0;//统计对的个数 

    for(int i=0,j=0,k=0;i<n;i++){
    p=fgets(a,n+1,ans);
    q=fgets(s,n+1,stu);
    if(strcmp(a,s)==0){
        right[j]=i+1;
        j++;
        num++;
    }
    else{
        wrong[k]=i+1;
        k++;
    }
    p++;
    q++;
    }
    printf("\nCorrect:%d(",num);
    fprintf(stu,"\nCorrect:%d(",num);
    for(int j=0;j<num;j++){
        fprintf(stu,"%d ",right[j]);
        printf("%d ",right[j]);
    }
    printf(")\n");
    fprintf(stu,")\n");

    printf("\nWrong:%d(",n-num);
    fprintf(stu,"\nWrong:%d(",n-num);
    for(int k=0;k<n-num;k++){
        printf("%d ",wrong[k]);
        fprintf(stu,"%d ",wrong[k]);
    }
    printf(")\n");
    fprintf(stu,")\n");
    fclose(ans);
    fclose(stu);
}

没有实现的功能:

①每道题目中出现的运算符个数我们只实现了单个运算符。

②程序一次运行生成的题目不能重复。

③程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt,统计结果输出到文件Grade.txt。但我们以另一种形式勉强实现了文件的答案比较。

 遇到的困难描述:

①数据结构不熟悉,没有运用结构体,我们的题目只能实现单个运算符。

②文件的读写格式不熟悉,导致fprintf不能正确打印,发现并已解决。

③细节的代码处理麻烦,比如减法,除法或者分数的话要判断它们的大小,然后调整数字。

五、测试代码:

①功能一的测试:

②功能二的测试:

程序能通过一万道题目的输出,但测试后发现程序运行时间比较长,还没有修改的想法。

六、小结

邓画月:

何颖琪:

因为写代码的经验不足,在合作过程中我会出一些差错,但是我的队友能很好的帮助我,使我在这次合作收获了更多的知识,这是做单人项目的时候我感受不到的。还有我自身的经验不足,导致这次工程的实现勉勉强强,今后会更加努力的学习新的语言和复习运用好c语言。

整体:合作期间整体工作安排还不够恰当,没有充分发挥好分工合作的性能,但我们有更多的经验交流和想法表达空间。

原文地址:https://www.cnblogs.com/vicky-3653/p/9732795.html

时间: 2024-10-19 00:23:06

结对四则运算编程(5212邓画月+5213何颖琪)的相关文章

20150401 作业2 结对 四则运算

结对 四则运算 编译环境:eclipse 开发人员:de 开发时间:2015-04-07 实现功能: 1.基本的加减乘除 2.每次出1道题目,提交后会显示是否答对,如果错了,还会出现正确答案 3.题目是随机的 4.能出于分数相关的运算以及可以输入真分数 5.可以控制题目的数量 缺点: 1.分数计算的答案输入分数格式才显示正确 2.不能用户选择做什么运算 3.还不能统计答题的时间 4.不能统计答题正确的数目 ...... 个人体会: 1.能力还是不足,一些东西想到了却不能实现 2.要多点和伙伴讨论

结对程序编程-四则运算

根据冯老师给出的作业我们解决了最基本的功能以及基本设定参数: 1) 题目的数量(个人项目的要求) 2) 数值的范围(个人项目的要求) 3) 题目中最多几个运算符 4) 题目中是否有乘除法 5) 题目中有无负数 我们本次两个小组合作完成本次作业,我们小组主要负责以下功能: 1) public void Build_NoMul_NoDiv_NoMinus函数 2) public void Build_Mul_Div_Minus函数 3)private string Getstr2函数 1.主要页面

结对-四则运算答题器-结对项目总结

项目地址:https://github.com/xyhcq/calc 结对成员: 学号:2015035107136 张良 学号:2015035107128 邢云淇 本次结对项目历时2个月,2位成员都是第一次从事结对编程,我们都能感到自己有了很大的收获,在结对编程的过程中,我们交换了一些自己的想法,发现了对方的一些想法优于自己的想法,互相学习了一番. 我们的结对项目为:四则运算答题器,能够根据用户输入的数值来界定出题的算数的最大值,同时可以控制生成计算题的数目,在生成题目后,由用户输入算式的答案来

结对-四则运算答题器-开发环境搭建过程

成员: 0:2015035107136-张良 1:2015035107128-邢云淇 结对项目:四则运算答题器 本次结对编程和团队项目我们都需要用python环境,为了便于书写代码,因此都选择了用pycharm这款ide 先准备好了Python和pycharm社区版安装包(社区版是免费的,功能够用了) 首先安装python2.7.5,一路下一步到finish结束,安装完成,环境变量已经自动配置好了,win+r运行python,成功运行,python环境搭建完毕. 选择安装路径 运行Python,

结对 四则运算

编译环境:Ecllipse 开发人员:朱浩龙 学号:201306114324 叶煜稳 学号:201306114323 博客:http://www.cnblogs.com/doubi2wy/ 最后开发时间:2015—04—09 实现功能: 可以出表达式里含有负整数(负整数最小不小于-100)的题目,且负数需要带括号,用户输入的结果不用带括号.如: 2*(-4) = -8 用户答题结束以后,程序可以显示用户答题所用的时间 用户可以选择出题的个数(最多不能超过5个题目),答题结束可以显示用户答错的题目

作业二——结对 四则运算

开发环境: VC++6.0队员:201306114407-吴哲永     20130611410-董大为功能:  1.用户可以选择出题的个数(最多不能超过5个题目),答题结束可以显示用户答错的题目个数和答对的题目个数 2.程序可以出单个整数阶乘的题目:如:4!=24 3.程序可以设置答题时间,时间设置为整数,单位为秒. 4.可以改变界面的颜色 5.程序可以出正整数四则运算,除法保留两位小数分工方面:这次我们结对并没有很明确分工,因为我们还是第一次合作,在很多方面都有不同风格,特别是在算法和传递便

实验二 结对四则运算

总结: 1.处理除法运算时要考虑除数不能为0的情况:2.设置了按钮要处理按钮监听事件:3.除法运算中要处理除不尽的情况,将结果设置为保留小数点后两位:4.判读第一个操作数与第二个操作数是否为负数并加括号时要分四种情况:5.处理时间计时的情况一定要将字符串转换为整型: 6.用if对答案进行判断时要将浮点型答案的条件放在前面,否则答案会出现问题: 7.按钮之间是互相独立的,不能嵌套使用: 心得体会: 这次的结对合作,让我也从别人的身上学到不一样的编程理念,明白自身的缺陷,有时候考虑一些问题仍不够全面

作业2 结对 四则运算

开发环境:Eclipse 实现功能: 1.程序可以出带括号的正整数四则运算,支持分数,除法保留两位小数,如:(1/3+1)*2 = 2.67,特别注意:这里是2.67而非2.66 2.用户可以选择出题的个数(最多不能超过5个题目),答题结束可以显示用户答错的题目个数和答对的题目个数 3.用户在第一次答题时,需要用户输入用户名,用户下次启动后,程序需要记住用户前一次输入的用户名 4.程序可以设置皮肤功能,可以改变界面的颜色即可. 结伴同学: 姓名:钟鹏昇 博客:http://www.cnblogs

《结对-四则运算答题器-结对项目总结》

通过2个多月的学习和努力终于做完了四则运算答题器,在这两个月的时间和我的队友学习到了很多,这2个多月我们共同成长. 在我们写代码的时候遇到各种各样的问题.如选难度时输入字母会报错等等,我们通过上网查资料.询问他人,解决了很多问题. 我们也通过这个项目深刻知道自身的不足,我们还差的很多,我希望我会继续学下去,变得更完美.