题目
本题要求编写程序,计算 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
分析
模拟 + 代码化
这道题真是到巨坑的题,第二个测试点找了我一天!
AC代码
//模拟 + 代码化
/*
分母为零加减法不能过
公约数为零乘除法不能过
float point expection -> 不能除0
mle or segmentation fault -> gcd传参不能一正一负,正数和负数是没有最大公因数的,同号之间才有最大公约数 -> gcd 传参是一定要都是正整数
不要用int,用ll,两个int相乘时可能爆longlong
测试样例
1.
-0/7 7/3
2.
0/5 0/8 除法爆
3.
12/10 15/12 第二个测试点
输入的两个数也要约分约彻底
错误输出:
12/10 15/12
1 2/10 + 1 3/12 = 2 9/20
1 2/10 - 1 3/12 = (-1/20)
1 2/10 * 1 3/12 = 1 1/2
1 2/10 / 1 3/12 = 24/25
正确输出
1 1/5 + 1 1/4 = 2 9/20
1 1/5 - 1 1/4 = (-1/20)
1 1/5 * 1 1/4 = 1 1/2
1 1/5 / 1 1/4 = 24/25
*/
/*
0 对任何数取模都等于 0
任意整数和0的公约数是该整数的所有约数
它们的最大公约数为该整数本身
因为0被所有非0整数整除,所以任意非零的整数都是0的约数
0与0的最大公约数是0
*/
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
string a, b;
ll a1, a2, b1, b2, fz, fm;
/*
若gcd传参是一正一负模拟程序
5 -3
-3 2 ->2 -3
-3 2 ->2 -3
-3 2
... 死循环
** 一个整数a,一个整数b
** if abs(a) < abs(b) -> a % b = a;
*/
inline ll gcd (ll a, ll b)
{
if(b > a) return gcd(b, a);
return b == 0 ? a : gcd(b,a % b);
}
inline ll lcm (ll a, ll b)
{
return a * b / gcd(a, b);
}
inline void out (char c)
{
if(a1 < 0) printf("(");
if(a1 == 0) printf("0");
else if(abs(a1) < abs(a2)) printf("%lld/%lld", a1, a2);
else if(a1 % a2 == 0) printf("%lld", a1 / a2);
else if(a1 % a2 != 0) printf("%lld %lld/%lld", a1 / a2, abs(a1) % a2, a2);
if(a1 < 0) printf(")");
printf(" %c ", c);
if(b1 < 0) printf("(");
if(b1 == 0) printf("0");
else if(abs(b1) < abs(b2)) printf("%lld/%lld", b1, b2);
else if(b1 % b2 == 0) printf("%lld", b1 / b2);
else if(b1 % b2 != 0) printf("%lld %lld/%lld", b1 / b2, abs(b1) % b2, b2);
if(b1 < 0) printf(")");
printf(" = ");
if(fz < 0) printf("(");
if(fz == 0) printf("0"); //0/8 15/4
else if(fm == 0) printf("Inf"); //5/3 0/6
else if(abs(fz) < abs(fm)) printf("%lld/%lld", fz, fm); //3/4
else if(fz % fm == 0) printf("%lld", fz / fm); //-4 2
else if(fz % fm != 0) printf("%lld %lld/%lld", fz / fm, abs(fz) % fm, fm); //-5 3
if(fz < 0) printf(")");
printf("\n");
}
inline void add ()
{
ll gbs = lcm(a2, b2);
ll gys = gcd(abs((gbs / a2) * a1 + (gbs / b2) * b1), gbs);
fz = ((gbs / a2) * a1 + (gbs / b2) * b1) / gys;
fm = gbs / gys;
out('+');
}
inline void sub ()
{
ll gbs = lcm(a2, b2);
ll gys = gcd(abs((gbs / a2) * a1 - (gbs / b2) * b1), gbs); //一个正数和一个负数没有公约数
fz = ((gbs / a2) * a1 - (gbs / b2) * b1) / gys;
fm = gbs / gys;
out('-');
}
inline void mul ()
{
fz = a1 * b1;
fm = a2 * b2;
ll gys = gcd(abs(fz), abs(fm));
fz = fz / gys;
fm = fm / gys;
out('*');
}
inline void div ()
{
fz = a1 * b2;
fm = a2 * b1;
//cout<<fz<<" "<<fm<<" "<<endl;
if(fz == 0 && fm == 0) //0/8 0/9
{
printf("0 / 0 = Inf\n");
return ;
}
ll gys = gcd(abs(fz), abs(fm));
fz /= gys;
fm /= gys;
if(fm < 0) {fm = -fm; fz = -fz;}
out('/');
}
int main ()
{
//***
scanf("%lld/%lld %lld/%lld", &a1, &a2, &b1, &b2);
//输入的分数也要约分输出 测试点2
ll gys_a = gcd(abs(a1), abs(a2));
a1 /= gys_a;
a2 /= gys_a;
ll gys_b = gcd(abs(b1), abs(b2));
b1 /= gys_b;
b2 /= gys_b;
add();
sub();
mul();
div();
return 0;
}