程序的实现思路:
1、产生随机的数字和运算符,这是组成题目的零件。
数字分为整数和真分数。需要注意的是,为了保证正确,真分数应该要检查(1)分母不为0,(2)不能约分;同时为了避免计算结果是NaN或∞的情况,出于程序简单考虑,生成的整数都是正数。
运算符是简单的四则运算。
2、调用1中的功能,生成题目并计算结果。
在这里控制参与运算的数的个数是随机的、某个位置生成整数还是分数也是随机的。生成题目只需要简单的循环调用就可以了。
计算题目结果使用转化为运算符前缀式的方法。因为开始写的时候没有考虑加括号,直接用函数返回值压栈计算,再在这个基础上加括号就不方便了。这里也可以看见,一个函数最好只实现一个功能。
3、输入输出部分。
首先在屏幕打印一个简单的界面,然后循环地输出题目、输入结果、判断正误,最后给出统计结果。
以下是代码和结果:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#define limit 30 //分母的范围
int n; //运算数的范围
int FindCommonFactor(int p,int q)
{//返回最大公因数,默认2<=p<q;
int i; //cursor
int commonfactor=1; //common factor
for(i=2;i<=p;i++)
{
if(p%i==0 && q%i==0)
{
commonfactor*=i;
p/=i;
q/=i;
i=2;
}
}
return commonfactor;
}
float ProperFraction(char *s,int *i)
{//生成真分数存入s中,返回生成的数
int p=0; //分子
int q=0; //分母
int cf; //common fraction
while(q==0 || q==1) //生成分母,分母不能是0或1
q=rand()%limit;
while(p==0) //生成分子,分子<分母且p!=0
p=rand()%q;
if(p>1) //格式化分数
{
cf=FindCommonFactor(p,q);
p/=cf;
q/=cf;
}
s[*i]='('; //存入字符串
(*i)++;
if(p<10)
{
s[*i]=p+'0';
(*i)++;
}
else
{
s[*i]=p/10+'0';
(*i)++;
s[*i]=p-(s[*i-1]-'0')*10+'0';
(*i)++;
}
s[*i]='/';
(*i)++;
if(q<10)
{
s[*i]=q+'0';
(*i)++;
}
else
{
s[*i]=q/10+'0';
(*i)++;
s[*i]=q-(s[*i-1]-'0')*10+'0';
(*i)++;
}
s[*i]=')';
(*i)++;
return (float)p/(float)q;
}
int Operator(char *s,int *i)
{//随机生成运算符,存入字符串,返回运算符编号
int o=rand()%4;
if(o==0) s[*i]='+';
if(o==2) s[*i]='-';
if(o==1) s[*i]='*';
if(o==3) s[*i]='/';
(*i)++;
return o%2+1;
}
int Decimal(char *s,int* i)
{//随机生成整数,存入字符串,返回这个整数
int num=0; //生成数
int tmp[10]={0}; //暂存数组
int j=0; //cursor
int substitude=0; //替身
while(num==0)
num=rand()%n;
substitude=num;
while(num>0) //反序按位拆开
{
tmp[j]=num%10;
num/=10;
j++;
}
for(j--;j>=0;j--) //存入字符串
{
s[*i]=tmp[j]+'0';
(*i)++;
}
return substitude;
}
int Rank(char x,char y){
//x>y return1; x<=y return0;
if(x=='+' || x=='-')
x=1;
if(x=='*' || x=='/')
x=2;
if(x=='#')
x=0;
if(y=='+' || y=='-')
y=1;
if(y=='*' || y=='/')
y=2;
if(y=='#')
y=0;
return (int)x>=(int)y;
}
float Question(char *s)
{//生成混合运算的字符串,返回计算结果
int i=0; //cursor
int j=0; //cursor
int DorF; //Decimal or Fraction
int len=0; //参与运算数的数量
char stack[11]="#"; //符号栈,栈底压入最低级的符号
float result[10]={0}; //结果栈
int stacktop=1; //符号栈顶
int resulttop=0; //结果栈顶
float newnum=0; //新生成数
while(len<2) //参与运算的数至少有2个
len=rand()%11;
for(j=0;j<len-1;j++)
{
DorF=rand()%2; //随机生成数
if(DorF)
newnum=(float)Decimal(s,&i);
else
newnum=ProperFraction(s,&i);
result[resulttop]=newnum; //新数入栈
resulttop++;
Operator(s,&i); //生成运算符
while(Rank(stack[stacktop-1],s[i-1])) //弹出运算符并计算
{
switch((int)stack[stacktop-1]) //计算
{
case '+':result[resulttop-2]+=result[resulttop-1];break;
case '-':result[resulttop-2]-=result[resulttop-1];break;
case '*':result[resulttop-2]*=result[resulttop-1];break;
case '/':result[resulttop-2]/=result[resulttop-1];break;
}
resulttop--; //修正结果栈
stacktop--; //弹出运算符
}
stack[stacktop]=s[i-1]; //新运算符入栈
stacktop++;
}
DorF=rand()%2;
if(DorF)
newnum=(float)Decimal(s,&i);
else
newnum=ProperFraction(s,&i);
result[resulttop]=newnum; //新数入栈
resulttop++;
while(stacktop>1) //剩下的计算
{
switch((int)stack[stacktop-1]) //计算
{
case '+':result[resulttop-2]+=result[resulttop-1];break;
case '-':result[resulttop-2]-=result[resulttop-1];break;
case '*':result[resulttop-2]*=result[resulttop-1];break;
case '/':result[resulttop-2]/=result[resulttop-1];break;
}
resulttop--; //修正结果栈
stacktop--; //弹出运算符
}
s[i]=0; //题目结束
return result[0];
}
float Trans(char *input){
int i=0; //cursor
int p=0; //分子
int q=0; //分母
float num=0; //数值
int neg=0; //负数
if(input[0]=='-')
{
neg=1;
i++;
}
while(input[i]!=0 && input[i]!='/')
{
p*=10;
p+=input[i]-'0';
i++;
}
if(input[i]==0)
num=(float)p;
else
{
i++;
while(input[i]!=0)
{
q*=10;
q+=input[i]-'0';
i++;
}
if(q<=0)
num=0.0/0.0;
else
{
if(p!=1 && FindCommonFactor(p,q)!=1)
num=0.0/0.0;
else
num=(float)p/(float)q;
}
}
return num;
}
int main(void) {
int i=0;//cursor
int questionnum=0; //题目数量
char question[100]={0}; //题目
float result=0.0; //题目结果
char input[50]={0}; //输入结果
int statistic=0; //统计正确量
float inputnum=0; //输入数值
for(;i<80;i++) //界面
printf("*");
printf("\n欢迎使用算式生成器!\n");
printf("\n请输入要求:\n");
printf("参与计算数的范围:");
scanf("%d",&n);
printf("生成算式的数量:");
scanf("%d",&questionnum);
printf("\n");
for(i=0;i<questionnum;i++) //生成题目并判断输入是否正确
{
srand (time(NULL));
result=Question(question);
printf("%s = ",question);
scanf("%s",input);
inputnum=Trans(input);
if(abs(inputnum-result)<=0.000005)
{
printf("correct!\n\n");
statistic++;
}
else
printf("error!\n\n");
}
printf("correct entry: %d\n",statistic); //统计结果
printf("accuracy: %.2f%%\n",((float)statistic*100)/questionnum);
return 0;
}