题目地址:
描述 编写一个 C 程序,实现两个分数的加减法 输入 输入包含多行数据 每行数据是一个字符串,格式是 "a/boc/d" 。 其中 a, b, c, d 是一个 0-9 的整数。 o 是运算符 "+" 或者 "-" 。 数据以 EOF 结束 输入数据保证合法 输出 对于输入数据的每一行输出两个分数的运算结果。 注意结果应符合书写习惯,没有多余的符号、分子、分母,并且化简至最简分数 样例输入 1/8+3/8 1/4-1/2 1/3-1/3 样例输出 1/2 -1/4
0
代码:
#include <stdio.h> typedef struct _Fraction { //分子 int numerator; //分母 int denominator; }Fraction; //处理数据,并打印结果 static void handlerData(Fraction *lhs,Fraction *rhs,char symbol); //通分 static void commonDenominator(Fraction *lhs,Fraction *rhs); //计算两个分数加 static Fraction subFraction(Fraction *lhs,Fraction *rhs); //计算两个分数减 static Fraction plusFraction(Fraction *lhs,Fraction *rhs); //计算a和b的最大公约数 static int calCommonDivisor(int a,int b); //计算a和b的最小公倍数 static int calCommonMultiple(int a,int b); int main() { int x1,y1,x2,y2; char symbol; do { scanf("%d/%d%c%d/%d",&x1,&y1,&symbol,&x2,&y2); Fraction lhs = {x1,y1}; Fraction rhs = {x2,y2}; handlerData(&lhs,&rhs,symbol); }while(getchar() != EOF); return 0; } //处理数据,并打印结果 static void handlerData(Fraction *lhs,Fraction *rhs,char symbol) { Fraction result; switch(symbol) { case '+': result = subFraction(lhs,rhs); break; case '-': result = plusFraction(lhs,rhs); } if(result.numerator != 0) { if(result.denominator != 1) { printf("%d/%d\n",result.numerator,result.denominator); } else { printf("%d\n",result.numerator); } } else { printf("0\n"); } } //通分 static void commonDenominator(Fraction *lhs,Fraction *rhs) { int commonNumber = calCommonMultiple(lhs->denominator,rhs->denominator); //分子乘以分母通分的倍数 lhs->numerator *= commonNumber / lhs->denominator; rhs->numerator *= commonNumber / rhs->denominator; //分母通分 lhs->denominator = commonNumber; rhs->denominator = commonNumber; } //计算两个分数加 static Fraction subFraction(Fraction *lhs,Fraction *rhs) { //先通分 commonDenominator(lhs,rhs); int tmpNumerator = lhs->numerator + rhs->numerator; int tmpDenominator = lhs->denominator; int tmpDivisor = calCommonDivisor(tmpNumerator,tmpDenominator); Fraction result; result.denominator = tmpDenominator/tmpDivisor; result.numerator = tmpNumerator / tmpDivisor; return result; } //计算两个分数减 static Fraction plusFraction(Fraction *lhs,Fraction *rhs) { //先通分 commonDenominator(lhs,rhs); int tmpNumerator = lhs->numerator - rhs->numerator; int tmpDenominator = lhs->denominator; int tmpSymbol = 1; if(tmpNumerator < 0) { tmpSymbol = -1; tmpNumerator *= -1; } int tmpDivisor = calCommonDivisor(tmpNumerator,tmpDenominator); Fraction result; result.denominator = tmpDenominator/tmpDivisor; result.numerator = tmpNumerator / tmpDivisor * tmpSymbol; return result; } //计算a和b的最大公约数 static int calCommonDivisor(int a,int b) { int maxNum = a>b?a:b; int minNum = a<b?a:b; int midResult = 0; while(minNum != 0) { midResult = maxNum % minNum; maxNum = minNum; minNum = midResult; } return maxNum; } //计算a和b的最小公倍数 static int calCommonMultiple(int a,int b) { int maxCommonDivisor = calCommonDivisor(a,b); return a*b/maxCommonDivisor; }
本题出错的地方有:
1.输入数据判断EOF,按照代码方式,唯一不方便的是采用了do..while...的方式。
2.输入数据的格式,开始采用了读取一行字符串的方式,在转换字符到数字的时候出错,不能使用atoi,atoi要求参数是char*,直接字符变量 str[i] - '0' 即可。
3.分母通分,是求的最小公倍数。而约分,是分子分母同时除以最大公约数。
4.commonDenominator 方法中,先求得最小公倍数,
此时需要先修改分子的值,最后再给分母赋最小公倍数的值。
5.两个数相加和两个数相减的时候,首先都是进行了通分,然后只需要进行分子的加减,分母要保证不变。
6.两个数相减的时候,分子只差有可能是0和负数的情况,如果是0则之前笔者写的求最大公约数的方法就是错误的返回了0
如上图代码,0是最小值,midResult余数的结果是0,然后返回了0.
这样导致分子分母除以最小公倍数的时候出错,因为分母是0的除法运算是非法的
所以最小公倍数的求解方法里面不应该返回0,本题目中的代码进行了判断,但是也不保证返回的是0.
7.最后反思求解的过程, 其实可以省去通分的步骤,学数学的时候,之所以先进行通分,是为了计算分子的时候,都是最小的数进行计算,但是计算机不在乎大数还是小数,只要保证在有效存储数值范围内即可,所以完全可以省略掉通分的过程以简化计算。直接将两个分母相乘进行最简单的通分运算来处理。
8.对测试数据的要求,至少需要3个数据,
a>b
a<b
a==b
9.容易忽略掉整数结果,比如
1/3+2/3
结果应该是
1
而如果不特殊处理的话,很容易输出为
1/1
也就是说分母是1的时候,要特殊处理