结对项目:四则运算
1、Github地址:https://github.com/JXQQQ/calculateHomework
项目成员:3218005038高子茵 3218005039江晓琦
2、项目要求
使用 -n 参数控制生成题目的个数。(已完成)
使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围。(已完成)
生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。(已完成)
每道题目中出现的运算符个数不超过3个。(已完成)
程序一次运行生成的题目不能重复。(未完成)
生成的题目存入执行程序的当前目录下的Exercises.txt文件。(已完成)
在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。(已完成)
程序应能支持一万道题目的生成。(已完成)
程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。(未完成)
3、效能分析
由于需求9没有完成,只完成了一个手动输入答案后对答案的需求;因此,在效能分析得时候我们删去对答案部分的代码,防止手动输入答案的时间造成影响。
如图分别为生成20、1000、10000道题所需要的时间。
4、设计实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?
5、代码说明。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 #include"head.h" 5 #include"function.c" 6 int an[3];//存入用户答案的全局变量 7 int main(struct formula f){ 8 int opernum;//符号数 9 int typeflag,operflag=0; 10 int r,i,j,k,t,n,repeat; 11 int bktflag=1; 12 int tnumber,numflag=1,m=0; 13 FILE *file; 14 createFile("Answers.txt"); 15 FILE *fp=fopen("Answers.txt","a+"); 16 struct num answers; 17 createFile("Exercises.txt"); 18 printf("\n"); 19 file=fopen("Exercises.txt","a+"); 20 if(file==NULL) { 21 printf("No File.\n"); 22 return 0;} 23 printf("please enter the range:\n"); 24 scanf("%d",&r); 25 printf("please enter the number of exercises:\n"); 26 scanf("%d",&tnumber); 27 struct formula fmls[tnumber+1]; 28 int ran[tnumber+1][3]; 29 srand(time(NULL)); 30 while(numflag<tnumber+1){ 31 opernum=rand()%3+1;//确定运算符数量 32 f.numcount=opernum+1;//运算数个数 33 for(i=0;i<4;i++) f.figure[i].den=1;//整数时分母为1 34 for(i=0;i<f.numcount;i++){ 35 f.figure[i].mol=rand()%r+1; 36 typeflag=rand()%100;//1时为真分数 37 if(typeflag==1) 38 f.figure[i].den=rand()%50+1; 39 if(f.figure[i].den==1||f.figure[i].mol%f.figure[i].den==0) 40 f.figure[i].den=rand()%r+1; 41 k=gcd(f.figure[i].mol,f.figure[i].den); 42 f.figure[i].mol=f.figure[i].mol/k; 43 f.figure[i].den=f.figure[i].den/k;//化简 44 }//确定运算数 45 for(i=0;i<4;i++){ 46 t=rand()%4; 47 switch(t){ 48 case 0:f.oper[i]='+';break; 49 case 1:f.oper[i]='-';break; 50 case 2:f.oper[i]='*';break; 51 case 3:f.oper[i]='/';break; 52 } 53 }//确定符号 54 for(i=0;i<5;i++) f.brackets[i]=0; 55 if(f.numcount==3){ 56 n=rand()%3; 57 switch(n){ 58 case 0: bktflag=0; 59 break; 60 case 1: { 61 for(i=0;i<4;i++) f.brackets[i]=0; 62 f.brackets[0]=1;f.brackets[1]=1;} 63 break; 64 case 2:{ 65 for(i=0;i<4;i++) f.brackets[i]=0; 66 f.brackets[1]=1;f.brackets[2]=1;} 67 break; 68 } 69 }//3个运算数 70 if(f.numcount==4){ 71 n=rand()%7; 72 switch(n){ 73 case 0:bktflag=0; 74 break; 75 case 1:{ 76 for(i=0;i<4;i++) f.brackets[i]=0; 77 f.brackets[0]=1;f.brackets[1]=1;} 78 break; 79 case 2:{ 80 for(i=0;i<4;i++) f.brackets[i]=0; 81 f.brackets[0]=1;f.brackets[2]=1;} 82 break; 83 case 3:{ 84 for(i=0;i<4;i++) f.brackets[i]=0; 85 f.brackets[1]=1;f.brackets[2]=1;} 86 break; 87 case 4:{ 88 for(i=0;i<4;i++) f.brackets[i]=0; 89 f.brackets[1]=1;f.brackets[3]=1;} 90 break; 91 case 5:{ 92 for(i=0;i<4;i++) f.brackets[i]=0; 93 f.brackets[2]=1;f.brackets[3]=1;} 94 break; 95 case 6:{ 96 for(i=0;i<4;i++) f.brackets[i]=1;} 97 break; 98 } 99 }//确定括号 100 for(i=1,repeat=0;i<=numflag;i++){ 101 if(ifRepete(f,fmls[i])==TRUE) { 102 repeat=1; 103 break; 104 } 105 } 106 if(repeat==1) break; 107 answers=calculateFml(f);//计算答案 108 if(answers.mol<0||answers.den<0){//舍去负值式子 109 continue; 110 } 111 printf("%d. ",numflag);//打印并录入式子和答案 112 fprintf(file,"%d. ",numflag); 113 printFormula(f); 114 fmlInFile(file,f); 115 fprintf(fp,"%d. ",numflag); 116 numInFile(fp,answers); 117 int g=gcd(answers.mol,answers.den);//将答案分解成三部分存入 118 if(g>1){ 119 answers.den/=g; 120 answers.mol/=g; 121 } 122 ran[numflag][2]=answers.den; 123 ran[numflag][0]=answers.mol/answers.den; 124 ran[numflag][1]=answers.mol%answers.den; 125 numflag++; 126 } 127 //输入答案 128 printf("Please input your answer:\n"); 129 int result[tnumber+1]; 130 for(i=1;i<=tnumber;i++){ 131 char input[10]; 132 struct num c1; 133 printf("%d. ",i); 134 fflush(stdin); 135 gets(input); 136 getAnswers(input); 137 result[i]=1;//判断对错 138 for(j=0;j<3;j++){ 139 if(an[j]!=ran[i][j]) {result[i]=0;break;} 140 } 141 } 142 int correct=0,wrong=0; 143 printf("Correct:("); 144 for(i=1;i<=tnumber;i++){ 145 if(correct>0) printf(","); 146 if(result[i]==1) { 147 printf("%d",i); 148 correct++; 149 } 150 } 151 printf("),共%d题\n",correct); 152 printf("Wrong:("); 153 for(i=1;i<=tnumber;i++){ 154 if(wrong>0) printf(","); 155 if(result[i]==0) { 156 printf("%d",i); 157 wrong++; 158 } 159 } 160 printf("),共%d题\n",wrong); 161 printf("\nOK:you can check the file.\n"); 162 return 0; 163 }
#ifndef TEST_H #define TEST_H #define NULL 0 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INTE 0 //整数 #define FRAC 1 //分数 #define MAXSIZE 10001 typedef int Status; struct num {//数据 int mol;//分子 int den;//分母(整数默认为1) }; struct formula{//式子 int numcount;//运算数的个数 struct num figure[4];//运算数的数组 char oper[4];//符号的数组(默认oper[0]==NULL) Status brackets[4];//括号数组 }; extern struct num calculateFml(struct formula fml); extern struct num getAnswer(char an[]); extern int an[3]; #endif
1 void createFile(char filename[]){//创建文件,已存在则覆盖 2 FILE *fp; 3 fp=fopen(filename, "w");//写入文件 4 if(fp==NULL) printf("文件创建失败"); 5 else printf("文件%s创建成功!",filename); 6 fclose(fp); 7 } 8 void printFormula(struct formula fml){//打印一个式子 9 int flag=0,bflag=0;//出现单括号时flag=1,已打印括号时bflag=1 10 int i; 11 for(i=0,flag=0;i<fml.numcount;i++){ 12 bflag=0; 13 if(i>0) { 14 if(fml.oper[i]=='/') printf("÷"); 15 else if(fml.oper[i]=='*') printf("×"); 16 else printf("%c",fml.oper[i]); 17 } 18 if(fml.brackets[i]==TRUE&&flag==0&&bflag==0){ 19 printf("("); 20 flag=1; 21 bflag=1; 22 } 23 printNum(fml.figure[i]); 24 if(flag==1&&fml.brackets[i]==TRUE&&bflag==0) { 25 printf(")"); 26 flag=0; 27 } 28 } 29 printf("=\n"); 30 31 } 32 void printNum(struct num c1){//真分数打印一个数 33 int g=gcd(c1.mol,c1.den); 34 if(g>1){ 35 c1.den/=g; 36 c1.mol/=g; 37 } 38 if(c1.den==1) printf("%d",c1.mol); 39 else if(c1.den<c1.mol){ 40 int z=c1.mol/c1.den; 41 int r=c1.mol%c1.den; 42 printf("%d'%d/%d",z,r,c1.den); 43 }else printf("%d/%d",c1.mol,c1.den); 44 return ; 45 } 46 void fmlInFile(FILE *fp,struct formula fml){//写入文件:式子 47 if(fp==NULL){ 48 printf("式子写入失败"); 49 }else{ 50 int flag,bflag=0;//出现单括号时为1 51 int i; 52 for(i=0,flag=0;i<fml.numcount;i++){ 53 bflag=0; 54 if(i>0) { 55 if(fml.oper[i]=='/') fprintf(fp,"÷"); 56 else if(fml.oper[i]=='*') fprintf(fp,"×"); 57 else fprintf(fp,"%c",fml.oper[i]); 58 } 59 if(flag==0&&fml.brackets[i]==TRUE&&bflag==0){ 60 fprintf(fp,"("); 61 flag=1; 62 bflag=1; 63 } 64 65 int g=gcd(fml.figure[i].mol,fml.figure[i].den);//打印式子中的数 66 if(g>1){ 67 fml.figure[i].den/=g; 68 fml.figure[i].mol/=g; 69 } 70 if(fml.figure[i].den==1) fprintf(fp,"%d",fml.figure[i].mol); 71 else if(fml.figure[i].den<fml.figure[i].mol){ 72 int z=fml.figure[i].mol/fml.figure[i].den; 73 int r=fml.figure[i].mol%fml.figure[i].den; 74 fprintf(fp,"%d'%d/%d",z,r,fml.figure[i].den); 75 }else fprintf(fp,"%d/%d",fml.figure[i].mol,fml.figure[i].den); 76 if(flag==1&&fml.brackets[i]==TRUE&&bflag==0) { 77 fprintf(fp,")"); 78 flag=0; 79 } 80 } 81 fprintf(fp,"=\n"); 82 } 83 return 0; 84 } 85 void numInFile(FILE *fp,struct num c1){//写入文件:真分数 86 if(fp==NULL){ 87 printf("数据写入失败"); 88 }else{ 89 int g=gcd(c1.mol,c1.den); 90 if(g>1){ 91 c1.den/=g; 92 c1.mol/=g; 93 } 94 if(c1.den==1) fprintf(fp,"%d",c1.mol); 95 else if(c1.den<c1.mol){ 96 int z=c1.mol/c1.den; 97 int r=c1.mol%c1.den; 98 fprintf(fp,"%d'%d/%d",z,r,c1.den); 99 }else fprintf(fp,"%d/%d",c1.mol,c1.den); 100 fprintf(fp,"\n"); 101 } 102 return ; 103 }
struct formula simplifyBracket(struct formula fml){//递归化简括号 int i=0; struct num temp; struct formula ff;; for(i=0;i<fml.numcount;i++){ if(fml.brackets[i]==TRUE){ int j,k,count; if(fml.brackets[i+1]==0) count=3; else count=2; if(count==2) {//括号中只有2数 temp=calculate(fml.figure[i],fml.figure[i+1],fml.oper[i+1]);//计算括号内式子 fml.figure[i]=temp; fml.brackets[i]=0; fml.numcount--; i++; for(;i<fml.numcount;i++){ fml.figure[i]=fml.figure[i+1]; fml.oper[i]=fml.oper[i+1]; fml.brackets[i]=fml.brackets[i+1]; } } if(count==3){ ff.numcount=count; k=i; for(j=0;j<3;j++,k++){ ff.figure[j]=fml.figure[k]; ff.oper[j]=fml.oper[k]; ff.brackets[j]=0; } ff=simplifyMD(ff); ff=simplifyAS(ff); fml.figure[i]=ff.figure[0]; fml.brackets[i]=0; if(i<fml.numcount-3){ fml.figure[i+1]=fml.figure[i+3]; fml.oper[i+1]=fml.oper[i+3]; fml.brackets[i+1]=fml.brackets[i+3]; } fml.numcount-=2; } fml=simplifyBracket(fml); } } return fml; } struct num calculate(struct num c1,struct num c2,char oper0){//两数运算 switch(oper0){ case'+': return addCount(c1,c2); case'-': return subCount(c1,c2); case'*': return mulCount(c1,c2); case'/': return divCount(c1,c2); default: printf("计算失效!"); return c1; } }
6、测试运行。
经过多次抽取题目进行人工运算,再与答案进行比对,得到答案与生成的答案一致。
7、PSP表格
PSP2.1 |
Personal Software Process Stages |
预估耗时(小时) |
实际耗时(小时) |
Planning |
计划 |
1 |
1.5 |
· Estimate |
· 估计这个任务需要多少时间 |
0.5 |
1 |
Development |
开发 |
38 |
48.2 |
· Analysis |
· 需求分析 (包括学习新技术) |
4 |
6 |
· Design Spec |
· 生成设计文档 |
1 |
1 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
0.2 |
0.2 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
0.8 |
1 |
· Design |
· 具体设计 |
3 |
4 |
· Coding |
· 具体编码 |
15 |
16 |
· Code Review |
· 代码复审 |
4 |
5 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
10 |
15 |
Reporting |
报告 |
2 |
3 |
· Test Report |
· 测试报告 |
1 |
2 |
· Size Measurement |
· 计算工作量 |
0.5 |
0.5 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
0.5 |
0.5 |
合计 |
|
40.5 |
51.7 |
8、项目小结
高子茵:本次结对项目中,学习到了很多平时做编程作业学习不到的东西。比如说关于file文件函数的使用。但是仍有问题没有解决,比如说在随机运算数的过程中控制 不好分数出现的概率;在本次结对项目中明白了注释的重要性,会比平时写多点的注释。跟搭档的配合挺好的,用腾讯会议一起改bug,有时候我的一些奇奇怪怪的错误她都能帮我找出来。
江晓琦:本次作业是我的第一次结对项目,我获得了很多宝贵的经验。项目开始之前我们讨论了很久,前期的任务分配和有效的沟通能大大提高我们的编程效率。我们选择了最熟悉的c语言,用结构体的方式定义式子和运算数。编程的过程并不顺利,依然需要边自学边编程,某些需求也没有完全实现,判重也只是最初步浅显的水平。我的搭档高子茵总是很耐心地跟我沟通、相互鼓励,有不懂的地方会及时给我帮助,即使我有因为表达不当而犯错的时候她也静下心来和我一起解决问题,一起修改代码。