20180925-6 四则运算试题生成
此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2148
代码的git地址:https://git.coding.net/wangyupan/second-program.git
我们利用随机数来产生字符串:
char GetStr() { int tmp; //char str[20]; int i; bool F=true; for( i=0; i<7; i++) { if(i%2==0) { if(F) { str1[i]=rand()%10+'0'; } else { while(1) { tmp=rand()%10; if(tmp) { str1[i]=tmp+'0'; break; } } } } else { str1[i]=Flag(); if(str1[i]=='/') F=false; else F=true; } } str1[i]='\0'; //return str; }
随机的字符串中添加括号:
int KH=rand()%5; switch(KH) { case 0: for(i=7; i>0; i--) str1[i]=str1[i-1]; for(i=8; i>4; i--) str1[i]=str1[i-1]; str1[0]='('; str1[4]=')'; str1[9]='\0'; break; case 1: for(i=7; i>0; i--) str1[i]=str1[i-1]; for(i=8; i>6; i--) str1[i]=str1[i-1]; str1[0]='('; str1[6]=')'; str1[9]='\0'; break; case 2: for(i=7; i>2; i--) str1[i]=str1[i-1]; for(i=8; i>6; i--) str1[i]=str1[i-1]; str1[2]='('; str1[6]=')'; str1[9]='\0'; break; case 3: for(i=7; i>2; i--) str1[i]=str1[i-1]; str1[2]='('; str1[8]=')'; str1[9]='\0'; break; case 4: for(i=7; i>4; i--) str1[i]=str1[i-1]; str1[4]='('; str1[8]=')'; str1[9]='\0'; break; default: break; }
利用后缀表达式来进行四则运算的实现:
float Pop2(Stack2 *S) { float num; if(S->top==NULL) { return 0; } Node2 *node=S->top; num=node->data; S->top=node->next; S->cnt--; free(node); return num; } float Arithmetic(char *str) { Stack1 opt; Stack2 opd; Init2(&opd); Init1(&opt); int tmp=0,i=0,j; //char str[50]; //scanf("%s",str); while(str[i]!='\0'||!Empty1(&opt)) { if(str[i]>='0'&&str[i]<='9') { tmp=tmp*10+str[i]-'0'; i++; if(str[i]<'0'||str[i]>'9') { Push2(&opd,tmp); tmp=0; } } else { if(Empty1(&opt)||(GetTop1(&opt)=='('&&str[i]!=')')||Prt(str[i])>Prt(GetTop1(&opt))) { Push1(&opt,str[i]); i++; continue; } if(GetTop1(&opt)=='('&&str[i]==')') { Pop1(&opt); i++; continue; } if((str[i]=='\0'&&!Empty1(&opt))||(str[i]==')'&&GetTop1(&opt)!='(')||Prt(str[i])<=Prt(GetTop1(&opt))) { switch(Pop1(&opt)) { case '+': Push2(&opd,Pop2(&opd)+Pop2(&opd)); break; case '-': j=Pop2(&opd); Push2(&opd,Pop2(&opd)-j); break; case '*': Push2(&opd,Pop2(&opd)*Pop2(&opd)); break; case '/': j=Pop2(&opd); Push2(&opd,Pop2(&opd)/j); } continue; } } } return Pop2(&opd); }
以上是实现功能一和功能二时的关键点,我们学习了四则运算相关的知识,看了一些如何生成随机的博客,实现了上面的代码。
实现功能三,主要就输打印输出到文本中,重复的试题不再出现,下面是关键代码:
FILE *fp; fp=fopen("f.txt","w+"); float Tans=Arithmetic(str1); //printf("2"); for(i=0; i<j; i++) { if(Tans==QE[i]) { flag=true; break; } } if(flag) { n++; continue; } QE[j++]=Tans; int len=strlen(str1); for(i=0; i<len; i++) { fprintf(fp,"%c",str1[i]); } fprintf(fp,"="); if(len==7) fprintf(fp," "); fprintf(fp,"%12.3f\n",Tans);
实现功能四时,感觉自己的思路一下子就断了,看了几篇博客之后,有了一个比较简单的思路,以下是实现的关键:
求最小公倍数,最大公因数:
int Cm(int a,int b,int c) { int m=a*b; while(b) { int tmp=a; a=b; b=tmp%b; } if(c==1) { return m/a; } return a; }
分数的四则运算:
if(Flag()=='+') { ans+=f; f1='+'; } else { ans-=f; f1='-'; } if(Flag()=='-') { ans-=g; f2='-'; } else { ans+=g; f2='+'; } int num1; //printf("1"); int gcd=Cm(b,h,1); if(Flag()=='+') { num1=a*gcd/b+c*gcd/h; f3='+'; } else { num1=a*gcd/b-c*gcd/h; f3='-'; } ans+=num1/gcd; int num2=num1%gcd; int num3=Cm(num2,gcd,2); num3=abs(num3); num2/=num3; gcd/=num3; if(tmp) { printf("%d/%d%c%d/%d%c%d%c%d=",a,b,f3,c,h,f1,f,f2,g); } else { printf("%d/%d%c%d/%d*%d%c%d%c%d= ",a,b,f3,c,d,e,f1,f,f2,g); } printf(" "); if(ans) { printf("%d ",ans); } if(num2) { printf("%d/%d",num2,gcd); } printf("\n");
感受:
与自己编写的时候还是不一样的吧,多一个脑子干这件事,思路要丰富一些。下面就是我们在写作业的时候遇到的比较重要的点:
1.我们在实现功能一是在想要不要用后缀表达式,朱珅莹觉得可以先不用,先写一个简单的实现加减乘除就可以,可以把功能一给实现了。我觉得要用后缀表达式,不然优先级的处理很麻烦,而且后边有括号的更处理不了。我们最终决定一开始就用后缀表达式来实现四则运算。
2.是否用随机数来生成试题,我们俩一开始都觉得可以手动书写试题,还可以避免随机数的不确定性。写了一段时间以后我觉得这样工作量太大,而且题库太有限,然后我们就利用了随机数。
3.编写程序时,我们遇到了这样一个情况,有个双层循环,满足内层循环里的条件就要跳出外层循环,我一筹莫展。然后朱珅莹就想到了利用一个变量,然后完美的解决了这个问题。果然多一个脑子是可以增加效率的。
4.编写功能四时,我们遇到了好多bug。处理复杂逻辑时,我们俩个人都处于懵逼状态。我们一点点的改,先改掉输出错的情况,然后负号在分母上的情况,一点点的改,bug越来越少,我们思路也渐渐清晰了。城墙一块一块砖垒起来的,bug是一个一个改掉的。
5.生成随机数时,我们忽略了除数不能为零,产生了诡异的bug,我们调了半天终于找了出来。真是粗心害死人呐。
结对编程时的照片