本题要求编写程序,计算 2 个有理数的和、差、积、商。
输入格式:
输入在一行中按照 a1/b1 a2/b2 的格式给出两个分数形式的有理数,其中分子和分母全是整型范围内的整数,负号只可能出现在分子前,分母不为 0。
输出格式:
分别在 4 行中按照 有理数1 运算符 有理数2 = 结果 的格式顺序输出 2 个有理数的和、差、积、商。注意输出的每个有理数必须是该有理数的最简形式 k a/b,其中 k 是整数部分,a/b 是最简分数部分;若为负数,则须加括号;若除法分母为 0,则输出 Inf。题目保证正确的输出中没有超过整型范围的整数。
输入样例 1:
2/3 -4/2
输出样例 1:
2/3 + (-2) = (-1 1/3)
2/3 - (-2) = 2 2/3
2/3 * (-2) = (-1 1/3)
2/3 / (-2) = (-1/3)
输入样例 2:
5/3 0/6
输出样例 2:
1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf
思路:题目本身不难,但是有很多坑的地方,我留在后面再说。整个题目其实要实现的功能只有一个,就是通过运算得到一个分数的分子和分母部分,再将其化简。化简的步骤如下:
1.先判断结果正负,即判断是否异号。这里不要用m*n<0,因为可能会溢出,测试点2(即第3个测试点)过不去的原因就在这里。
2.得到整数部分,根据是否为0再分情况。
3.得到分数部分,如果分数部分为0则直接输出,否则需要化简,先求分子和分母的最大公约数,再让分子和分母分别除以它。
#include <iostream>
using namespace std;
long long gcd(long long a, long long int b) {//求最大公约数
if (b == 0) return a;
else return gcd(b, a % b);
}
void func(long long m, long long n) {//m为分子,n为分母,化简
if (m * n == 0) {//如果两者至少其中一个为0
printf("%s", n == 0 ? "Inf" : "0");
return;
}
bool flag = ((m < 0 && n > 0) || (m > 0 && n < 0));//判断是否异号
m = abs(m);
n = abs(n);
long long k = m / n;//求整数部分
if (!k) {//整数部分为0
m -= k * n;//提出整数部分后的分子
long long t = gcd(m, n);
m /= t; n /= t;//约分
if (!flag) printf("%lld/%lld", m, n);//结果为正
if (flag) printf("(-%lld/%lld)", m, n);//结果为负
} else {//整数部分不为0
if (m % n == 0) {//能直接除尽
if (!flag) printf("%lld", k);
else printf("(-%lld)", k);
return;
}
m -= k * n;//提出整数部分后的分子
long long t = gcd(m, n);
m /= t; n /= t;//约分
if (!flag) printf("%lld %lld/%lld", k, m, n);//结果为正
if (flag) printf("(-%lld %lld/%lld)", k, m, n);//结果为负
}
}
int main() {
long long a1, a2, b1, b2;
scanf("%lld/%lld %lld/%lld", &a1, &b1, &a2, &b2);
func(a1, b1); printf(" + "); func(a2, b2); printf(" = "); func(a1 * b2 + b1 * a2, b1 * b2); printf("\n");
func(a1, b1); printf(" - "); func(a2, b2); printf(" = "); func(a1 * b2 - b1 * a2, b1 * b2); printf("\n");
func(a1, b1); printf(" * "); func(a2, b2); printf(" = "); func(a1 * a2, b1 * b2); printf("\n");
func(a1, b1); printf(" / "); func(a2, b2); printf(" = "); func(a1 * b2, b1 * a2);
return 0;
}
坑点与反思:
1.一开始我用的头文件是cstdio和cmath,但是测试点2和3(即最后两个测试点)都过不去,我在牛客网上编译甚至会报错,提示我使用fabs,然后居然就可以过了,但是编译器会出现提示fabs的问题。也不知道是long long和取绝对值函数之间有什么问题。
2.后面我网上查阅了一下其他人的做法,发现用头文件iostream和cmath,再using namespace std; 使用abs函数就没有任何问题和提示。并且iostream头文件里包含了cmath,所以可以像我答案那样使用。
3.为了避免这种问题,可以用#include <bits/stdc++.h> 和using namespace std。