2018软件工程第五次作业(结对二)

结对作业:小学计算题生成程序

一、题目要求

我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:
能够自动生成四则运算练习题

  • 可以定制题目数量
  • 用户可以选择运算符
  • 用户设置最大数(如十以内、百以内等)
  • 用户选择是否有括号、是否有小数
  • 用户选择输出方式(如输出到文件、打印机等)
  • 最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)

二、角色选择

  • 驾驶员:何涛
    完成全部代码工作,程序基本实现全部要求功能,并将代码上传至coding.net或者GitHub代码托管系统中;对导航员在本次编程工作中起到的作用给出客观评价,并完成500字以上的总结。
  • 领航员:刘子君
    辅助驾驶员完成全部代码工作,并且为关键函数选用合适的覆盖标准设计测试用例,并编写代码进行单元自动测试;根据上次作业的代码检查表对驾驶员的本次工作进行评价;对本次工作完成500字以上的总结。

三、需求分析

小学计算题有什么?我们都做过。无非就是整数、分数、小数这些题型。老师每天都要出大量的题给学生做,老师很苦恼啊。
这次作业就是解决老师的苦恼——一个小可以自动生成小学计算的程序,可以按照老师的需求生成不同题型(可选择整数、分数、小数、复合运算)并且可以将题目和答案保存到文件中。

四、过程分析

注:框里的功能是重复的。

五、关键代码实现

  • 1、整数运算
    for (i =0;i < total;i++)
    {
        a = rand() % mmax + 1;//生成随机整数
        b = rand() % mmax + 1;//生成随机整数
        char cha = ch[rand () % cnum];//生成随机符号
		printf("%d %c %d =\n",a,cha,b);//打印表达式
		fprintf(fp,"%d %c %d =\n",a,cha,b);//写入文件
		if(cha == '+')//计算结果
		{
			s1[i] = a + b;
			s2[i] = 0;
		}
	    if(cha == '-')
		{
			s1[i] = a - b;
			s2[i] = 0;
		}
		if(cha == '*')
		{
			s1[i] = a * b;
			s2[i] = 0;
		}
		if(cha == '/')
		{
			s1[i] = a / b;//商
			s2[i] = a % b;//余数
		}
    }
    for(int i = 0;i < total;i++)//输出结果,写入文件
	{
		if(s2[i] == 0)//余数是否为零
		{
			printf("%d\t",s1[i]);
		    fprintf(fp,"%d \n",s1[i]);
		}
		else
		{
			printf("%d......%d\t",s1[i],s2[i]);
			fprintf(fp,"%d......%d\n",s1[i],s2[i]);
		}
	}
  • 2、分数运算
for (int i = 0;i < total;i++)
    {
        a =rand() % mmax + 1;//第一个分数的分子
        b =rand() % mmax + a;//第一个分数的分母
        c =rand() % mmax + 1;//第二个分数的分子
        d =rand() % mmax + c;//第二个分数的分母
        char cha = ch[rand () % cnum];
        printf("(%d/%d) %c (%d/%d)=\n",a, b,cha,c,d);
        fprintf(fp,"(%d/%d) %c (%d/%d)=\n",a, b,cha,c,d);
        if(cha == '+')//分数运算
		{
			s1[i] = a * d + c * b;
			s2[i] = b * d;
		}
        if(cha == '-')
		{
			s1[i]= a * d - c * b;
			s2[i] = b * d;
		}
        if(cha == '*')
		{
			s1[i] = a * c;
			s2[i] = b * d;
		}
        if(cha == '/')
		{
			s1[i] = a * d;
			s2[i] = b * c;
		}
    }
    for(i = 0;i < total;i++)
	{
		printf("(%d/%d)\t",s1[i],s2[i]);
		fprintf(fp,"(%d/%d)\n",s1[i],s2[i]);
	}

注:结果没有约分,不是最简分数

  • 3、小数运算
for (i = 0;i < total;i++)
    {
    	e = rand() /(double)(RAND_MAX/mmax);//随机小数 
	    f = rand() /(double)(RAND_MAX/mmax);//随机小数 
	    char cha = ch[rand () % cnum];
	    printf("%.2f %c %.2f=\n", e,cha,f);//只保留小数点后两位
        fprintf(fp,"%.2f %c %.2f=\n", e,cha,f);
	    if(cha == '+')//小树运算
			s3[i]= e+f;
        if(cha == '-')
		    s3[i] = e-f;
		if(cha == '*')
		   s3[i] = e-f;
		if(cha == '/')
		   s3[i] = e/f;
    }
    for(int i = 0;i < total;i++)
	{
		printf("%.2f\t",s3[i]);
		fprintf(fp,"%.2f\n",s3[i]);
	}

注:小数在输出表达式时为两位小数,但是计算结果时却是六位小数运算。由于舍入问题,部分输出结果与表达式运算结果会有0.01的误差,暂时没想出好的办法来解决。

  • 4、复合运算
for (i = 0;i < total;i++)
    {
    	a = rand() % mmax + 1;
        b = rand() % mmax + 1;
        c = rand() % mmax + 1;
	    char cha1 = ch[rand () % cnum];
	    char cha2 = ch[rand () % cnum];
	    int n = rand() % 2 + 1;//固定两种格式,随机出现一种
        switch (n)
        {
        case 1:
            printf("(%d  %c %d) %c %d=\n", a, cha1,b,cha2,c);
            fprintf(fp,"(%d  %c %d) %c %d=\n", a, cha1,b,cha2,c);
            if(cha1 == '+')
				p = a + b;//p为临时变量,暂存括号内的结果
		    else if(cha1 == '-')
			    p = a - b;
		    else if(cha1 == '*')
			    p = a * b;
		    else if(cha1 == '/')
			    p = a / b;

		    if(cha2 == '+')
		   	    s1[i] = p + c;
			else if(cha2 == '-')
		   	    s1[i] = p - c;
			else if(cha2 == '*')
		   	    s1[i] = p * c;
			else if(cha2 == '/')
		   	    s1[i] = p / c;
			break;
        case 2:
            printf("%d  %c (%d %c %d)=\n", a, cha1,b,cha2,c);
            fprintf(fp,"%d  %c (%d %c %d)=\n", a, cha1,b,cha2,c);
            if(cha1 == '+')
				p = b + c;
		    else if(cha1 == '-')
			    p = b - c;
		    else if(cha1 == '*')
			    p = b * c;
		    else if(cha1 == '/')
			    p = b / c;

		    if(cha2 == '+')
		   	    s1[i] = a + p;
			else if(cha2 == '-')
		   	    s1[i] = a - p;
			else if(cha2 == '*')
		   	    s1[i] = a * p;
			else if(cha2 == '/')
		   	    s1[i] = a / p;
            break;
        }
    }
    for(int i = 0;i < total;i++)
	{
		printf("%d\t",s1[i]);
		fprintf(fp,"%d\n",s1[i]);
	}

注:在进行除法运算时,带着余数进行运算很不方便,所以只求出商进行运算就可以。

六、感想

在刚看到这个题目的时候,我以为不就是循环语句吗,很简单。但是等真正开始做的时候才发现没有那么简单。首先随机数怎么产生,其次随机符号怎么产生,结果怎么运算等等一大堆问题都出现了。没办法只能去翻书找了,但是在书里没有找到,只能上网找了。这个时候我才知道自己的基础究竟多差。在课上学的那些都是基础的基础,在课外还要找些书来给提升自己,不多看书还是不行的。同时要是想掌握更多的知识,还要多编程,我认为在做中学比只看书不练习在实际编程应方面要强很多。
我的结对伙伴是我班的刘子君同学。我们两个人沟通起来很好,编程能力差不多,编程氛围也很好,一起分析程序一起找bug。我们两个人对作业的态度也比较认真的,还算是比较顺利的完成了作业。
我认为结对编程主要有不少好处:首先起到督促的作用。这主要是因为如果我一个人编程,可能会出现消极的情绪,而两个人共同编程会起到促进作用。其次对函数的语句能进一步优化,在自己敲代码时,另一个人可以反思代码有什么问题、哪里可以优化,这些都够使代码质量得到很大的提升。最后是更有效的找错,我要找出自己写的bug是一件很困难的事情。但是有伙伴在一个不同的视角寻找问题,就能很快地找到一些我不易发现的bug。最后能够互相学习,共同提高。在结对编程中,可以发现队友在编程中的很多好习惯以及心得,如果能够吸收这些东西为己用,便能够显著提高自己的编程水平。

七、链接

查看代码请点这里
运行结果、单元测试、代码审查表,请点这里

八、照片

posted @ 2018-04-14 16:04  long-long-ago  阅读(235)  评论(0编辑  收藏  举报