结对项目-四则运算(C语言实现)

一.github项目地址:https://github.com/HLyxd/my-app1

二.PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划50    60
· Estimate· 估计这个任务需要多少时间4040
Development开发1250 1320
· Analysis· 需求分析 120120
· Design Spec· 生成设计文档6080
· Design Review· 设计复审 5080
· Coding Standard· 代码规范6060
· Design· 具体设计120110
· Coding· 具体编码850 950
· Code Review· 代码复审 70 90
· Test· 测试(自我测试,修改代码,提交修改) 120 120
Reporting报告 120 120
· Test Report· 测试报告 50 50
· Size Measurement· 计算工作量 40 40
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划 4050
合计  2930 3290

三.效能分析

本次作业因为我们两人的编程能力都不是那么强,所以很多地方的设计上都不是那么简洁,效能分析也完成得不是那么好,有粗略估计一下每次生成题目的时间都在1到2秒,当然,这是在生成的题目并不是那么多的情况,当输入10000的时候,差不多花了九到十秒左右。总体上效能分析我们这个板块做得不不好。

四.解题思路分析

首先拿到题目的时候,在还没组队的时候我们分别有对题目做出自己的见解和解题思路,所以当我们组队的时候我们有先做讨论,各自提出对题目各个要求的自己想法,我们对各个要求的解决方案都有大致想到,有实际上的编程却有一部分没能实现,这一点是受限于我们两人的编程能力不太强。题目是随机生成四则运算,首先我们就是设置一个随机数,这个随机数的取值范围由1到2(因为此次我们实现的顶多为两个运算符),然后再用switch语句根据生成的值转入到对应的运算符数量函数,加减乘除号的随机生成运用了rand函数来随机生成一个1到4的变量,分别对应加号,减号,乘号,除号,在这里当运算符为除号的时候我们采用了辗转相除法,写一个gcd函数来求出两个数的最大公约数,这样来实现输出分数的要求,生成答案和试题文件的话,我们则是通过先定义两个文件指针,指向相对应要写入的文件(Answer.txt和Exercise.txt),然后生成文件并打开文件,通过fprinft将生成的题目和答案写入到相应的文件。

五.代码说明

operationone函数是当运算符为一个时候的情况下,通过随机生成的运算符类型(一到四分别对应加减乘除),然后转入到相对应的情况

int operationone(int numb1,int numb2,int max,int i)	//不一定是整型函数
	{	
		int gcd(int numb1,int numb2);
		int temp;//中间值
		int result;
		op1=rand()%4+1;	//op1的生成值为1到4,分别对应加法,减法,乘法,除法
		fb=fopen("Exercises.txt","a");
		fp=fopen("Answers.txt","a");//打开文件
		switch(op1){
			case 1:		//op1为1的时候,执行加法操作
				result=numb1+numb2;
				fprintf(fp,"题目%d:%d+%d=%d\n",i,numb1,numb2,result);		//写入文件
			    fclose(fp);			//关闭文件
				fprintf(fb,"题目%d:%d+%d=\n",i,numb1,numb2);		
			    fclose(fb);	
				break;
			case 2 :		//op1为2的时候,执行减法操作;
				if(numb1<numb2)		//为保证结果不为零,当出现生成的被减数比减数小,进行两者值的交换
				{
				temp=numb1;
				numb2=numb1;
				numb1=temp;
				}
				result=numb1-numb2;
				fprintf(fp,"题目%d:%d-%d = %d\n",i,numb1,numb2,result);
			    fclose(fp);
				fprintf(fb,"题目%d:%d-%d = \n",i,numb1,numb2);
			    fclose(fb);
				break;
			case 3 :		//op1为3的时候,执行乘法操作;
				result=numb1*numb2;
				fprintf(fp,"题目%d:%d*%d = %d\n",i,numb1,numb2,result);
			    fclose(fp);
				fprintf(fb,"题目%d:%d*%d = \n",i,numb1,numb2);
			    fclose(fb);
				break;
			case 4 :		//op1为4的时候,执行除法操作;
				if(numb2==0)
					numb2=rand()%max+1;
				temp=gcd(numb1,numb2);
				fprintf(fp,"题目%d:%d/%d = %d/%d\n",i,numb1,numb2,numb1/temp,numb2/temp);
			    fclose(fp);
				fprintf(fb,"题目%d:%d/%d = \n",i,numb1,numb2);
			    fclose(fb);
				break;
			default:printf("ERROR\n");
		}
		return 0;
	}
知识兔

 

gcd辗转相除法

int gcd(int numb1,int numb2)//辗转相除法 
    {
        if(numb2==0) return numb1;
        return    gcd(numb2,numb1%numb2);
    }
知识兔

运算符为两个的情况下:

int operationtwo(int numb1,int numb2,int numb3,int max)
    {    
        int gcd(int numb1,int numb2);
        int result, result1,temp,temp1;
        op1=rand()%4+1;        
        op2=rand()%4+1;                        //op1,op2的生成值为1到4,分别对应加法,减法,乘法,除法
        fp=fopen("Answers.txt","a");
        fb=fopen("Exercises.txt","a");
        switch(op1){
            case 1 :        
                switch(op2){
                case 1 :                    //op1,op2均为加法的情况
                    result1=numb1+numb2;
                    result=result1+numb3;
                    fprintf(fp,"题目%d:%d+%d+%d%=%d\n",i,numb1,numb2,numb3,result);
                    fclose(fp);
                    fprintf(fb,"题目%d:%d+%d+%d%=\n",i,numb1,numb2,numb3);
                    fclose(fb);
                    break;
                case 2 :                    //op1为加法,op2为减法的情况
                    result1=numb1+numb2;
                    if(result1<numb3)
                    {
                        temp=numb3;
                        numb3=numb2;
                        numb2=temp;
                    }
                    result=numb1+numb2-numb3;
                    fprintf(fp,"题目%d:%d+%d-%d=%d\n",i,numb1,numb2,numb3,result);
                    fclose(fp);
                    fprintf(fb,"题目%d:%d+%d-%d%=\n",i,numb1,numb2,numb3);
                    fclose(fb);
                    break;
                case 3 :                    //op1为加法,op2为乘法的情况
                    result1=numb2*numb3;
                    result=numb1+result1;
                    fprintf(fp,"题目%d:%d+%d*%d=%d\n",i,numb1,numb2,numb3,result);
                    fclose(fp);
                    fprintf(fb,"题目%d:%d+%d*%d%=\n",i,numb1,numb2,numb3);
                    fclose(fb);
                    break;
                case 4 :                    //op1为加法,op2为除法的情况
                    if(numb3==0)
                    {
                    numb3=rand()%max+1;
                    }
                    temp=gcd(numb2,numb3);
                    fprintf(fp,"题目%d:%d+%d/%d=%d'%d/%d\n",i,numb1,numb2,numb3,numb1,numb2/temp,numb3/temp);
                    fclose(fp);
                    fprintf(fb,"题目%d:%d+%d/%d%=\n",i,numb1,numb2,numb3);
                    fclose(fb);
                    break;
                default:printf("ERROR\n");
                }
                break;
            case 2 :        
                switch(op2){
                    case 1 :                    //op1为减法,op2为加法的情况
                        if(numb1<numb2)            //为保证结果不为零,当出现生成的被减数比减数小,进行两者值的交换
                        {
                            temp=numb1;
                            numb2=numb1;
                            numb1=temp;
                        }
                        result=numb1-numb2+numb3;
                        fprintf(fp,"题目%d:%d-%d+%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d-%d+%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 2 :                    //op1为减法,op2为减法的情况
                        do{
                        numb1=rand()%max;
                        numb2=rand()%max;
                        numb3=rand()%max;
                        }while((numb1-numb2-numb3)<=0);
                        result=numb1-numb2-numb3;
                        fprintf(fp,"题目%d:%d-%d-%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d-%d-%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 3 :                    //op1为减法,op2为乘法的情况
                        do{
                        numb1=rand()%max;
                        numb2=rand()%max;
                        numb3=rand()%max;
                        }while((numb1-numb2*numb3)<0);
                        result=numb1-numb2*numb3;
                        fprintf(fp,"题目%d:%d-%d*%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d-%d*%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 4 :                    //op1为减法,op2为除法的情况
                        do{
                        numb1=rand()%max;
                        numb2=rand()%max;
                        numb3=rand()%max;
                        }while((numb1-numb2/numb3)<0||numb3==0);
                        result=numb1-numb2/numb3;
                        fprintf(fp,"题目%d:%d-%d/%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d-%d/%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                default:printf("ERROR\n");
                }
                break;
            case 3 :        
                switch(op2){
                    case 1 :                    //op1为乘法,op2为加法的情况
                        result=numb1*numb2+numb3;
                        fprintf(fp,"题目%d:%d*%d+%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d*%d+%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 2 :                    //op1为乘法,op2为减法的情况
                        do{
                        numb1=rand()%max;
                        numb2=rand()%max;
                        numb3=rand()%max;
                        }while((numb1*numb2-numb3)<0);
                        result=numb1*numb2-numb3;
                        fprintf(fp,"题目%d:%d*%d-%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d*%d-%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 3 :                    //op1为乘法,op2为乘法的情况
                        result=numb1*numb2*numb3;
                        fprintf(fp,"题目%d:%d*%d*%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d*%d*%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 4 :                    //op1为乘法,op2为除法的情况
                        do{
                        numb3=rand()%max;
                        }while(numb3==0);
                        temp1=numb1*numb2;
                        temp=gcd(temp1,numb3);
                        fprintf(fp,"题目%d:%d*%d/%d=%d/%d\n",i,numb1,numb2,numb3,temp1/temp,numb3/temp);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d*%d/%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                default:printf("ERROR\n");
                }
                break;
            case 4 :        
                switch(op2){
                    case 1 :                    //op1为除法,op2为加法的情况
                        do{
                        numb2=rand()%max;
                        }while(numb2==0);
                        temp=gcd(numb1,numb2);
                        fprintf(fp,"题目%d:%d/%d+%d=%d'%d/%d\n",i,numb1,numb2,numb3,numb3,numb1/temp,numb2/temp);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d/%d+%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 2 :                    //op1为除法,op2为减法的情况
                        do{
                        numb3=rand()%max;
                        }while(    (numb1/numb2-numb3)<0||numb2==0);
                        result=numb1/numb2-numb3;
                        fprintf(fp,"题目%d:%d/%d-%d=%d\n",i,numb1,numb2,numb3,result);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d/%d-%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 3 :                    //op1为除法,op2为乘法的情况
                        do{
                        numb2=rand()%max;
                        }while(numb2==0);
                        temp1=numb1*numb3;
                        temp=gcd(temp1,numb2);
                        result=numb1/numb2*numb3;
                        fprintf(fp,"题目%d:%d/%d*%d=%d/%d\n",i,numb1,numb2,numb3,temp1/temp,numb2/temp);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d/%d*%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                    case 4 :                    //op1为除法,op2为除法的情况
                        do{
                        numb2=rand()%max;
                        numb3=rand()%max;
                        }while(numb3==0||numb2==0);
                        result=numb1/numb2/numb3;
                        temp1=numb2*numb3;
                        temp=gcd(temp1,numb1);
                        fprintf(fp,"题目%d:%d/%d/%d=%d/%d\n",i,numb1,numb2,numb3,numb1/temp,temp1/temp);
                        fclose(fp);
                        fprintf(fb,"题目%d:%d/%d/%d%=\n",i,numb1,numb2,numb3);
                        fclose(fb);
                        break;
                default:printf("ERROR\n");
                }
                break;
            default:printf("ERROR\n");
        }
        return 0;
    }
知识兔

主函数通过获取输入的题目数量和随机生成值的最大数,并将数值传到相对应用到的函数:

int main()
    {
        int subnumber,max;
        int opnum;
        int operationone(int numb1,int numb2,int max,int i);        //函数的声明
        int operationtwo(int numb1,int numb2,int numb3,int max,int i);
        FILE *fp;
        fp=fopen("Exercises.txt","w");
        fp=fopen("Answers.txt","w");            //建立文件
        fclose(fp);
        srand((unsigned)time(0));                //为保证每次运行程序的时候生成的题目都不一样
        printf("************随机生成四则运算题目************\n");
        printf("请输入题目数量:\n");
        scanf("%d",&subnumber); 
        printf("请输入生成的随机数范围大小:\n");
        scanf("%d",&max); 
        for(i=1;i<=subnumber;i++)        //for循环生成题目
        {
            opnum=rand()%2+1;
            switch(opnum)        
            {
            case 1 :                            //当随机数是生成1个运算符时
                numb1=rand()%max;
                numb2=rand()%max;
                operationone(numb1,numb2,max,i);        //执行函数的同时得同时执行把表达式输出到txt文件中
                break;
            case 2 :            //当随机数是生成2个运算符时
                numb1=rand()%max;
                numb2=rand()%max;
                numb3=rand()%max;
                operationtwo(numb1,numb2,numb3,max,i);
                break;    
            default:printf("ERROR\n");
            }
        }
        return 0;
    }
知识兔

六.测试运行

主界面:

 生成的Answers.txt文件:

 生成的Exercices.txt文件:

生成一万道题目:

七.项目总结

这一次的结对编程让我们懂得了结对编程的意义所在,也更好地感受到编程的乐趣,,通过两个人的分工合作体会到软件工程确实不简单,虽然是两个人而已,但我们感觉到团队配合是多么重要,这次的作业中我们也有很多地方要求没实现,真分数的地方我们只实现了一到两个运算符的输出,当然三个运算符的实现我们是有思路的,我们在网上有对应查到用栈实现,但因为数据结构学得不好,不太会运用,这也坚定我们得学好相关知识的决心,总得来说,虽然这次作业完全度不是那么完美,但我们还是从中学到了不少东西,也期待下一次的团队作业能从中学到更多东西。

计算机