1034 有理数四则运算 (20分) 浮点数错误

本题要求编写程序,计算 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

又是一题一下午的一天。wa的时候多难过,ac的时候就有多开心。
这题有很多的细节,我开始浮点数错误就是因为没用long long
之前的一些处理多写几个if else 就好了。加油啊!!!
这里我把这题的解决分成了很多个小部分,每部分写了个函数,希望可以方便你的阅读,以及让你更好地理解。一些细节见注释

#include<cstdio>
/*1.先对输入的两个有理数进行化简,分子为0输出0,分母为1输出整数
  2.计算,并化成带分数的形式
  注意:
  1.有理数、带分数为负数要加括号
  2.要用long long,不然会浮点数错误	也就是溢出,开始以为是除0错误,结果判断半天,改成long long后,ac了 黑人问号??
  3.这题有很多细节要注意。见注释
  */
typedef long long ll;
ll gcd(ll a, ll b)
{
	return !b ? a : gcd(b, a % b);
}
typedef struct RationalNum {//这里我用结构体存储一个有理数
	ll a, b, k;
	RationalNum() : k(0) {}
} Rnum;
ll f = 1;//判断有理数是否是负数 f=-1则是负数
void Simplify(Rnum& num);//简化一个有理数
void Outone(Rnum num);//输出一个有理数
void OutAll(Rnum  n1, Rnum n2, Rnum n3, char c);//输出一个等式
void Calculate(Rnum n1, Rnum n2);//四则运算
int main()
{
	//freopen("in.txt", "r", stdin);
	Rnum n1, n2;
	scanf("%lld/%lld%lld/%lld", &n1.a, &n1.b, &n2.a, &n2.b);
	Calculate(n1, n2);
	return 0;
}
void Simplify(Rnum& num)
{
	f = 1;
	if (num.b < 0)
	{//虽然输入的时候保证负号在分子前,但你计算得到的n3,可不会自动挪负号,所以还是要判断一下
		num.a = -num.a;
		num.b = -num.b;
	}
	if (num.a < 0) {
		num.a = -num.a;
		f = -f;//表明是负数
	}
	ll x = gcd(num.a, num.b);
	num.a /= x;
	num.b /= x;
	if (num.a >= num.b) {
		num.k = f * (num.a / num.b); //哪怕f=-1,当该数是真分数,k也会是0.那么负号就被省去了这我当时一直错的地方
		num.a %= num.b;
	}
}
void Outone(Rnum num)
{//输出一个时先简化,再输出.输出还是要考虑一些东西的,可以自己模拟一下
	Simplify(num);
	if (num.k < 0) printf("(");
	if (num.k) printf("%lld", num.k);
	/*注意一下这个情况,可能例如 -1/3的情况,被化简后=>k=0,f=-1,a=1,b=3,那么如果不特判,会输出1/3
	所以要特判真分数是负的情况*/
	else if (num.k == 0 && f == -1) printf("(-");
	if (num.a == 0) {//a=0,不用再管b是什么了
		if (num.k == 0) printf("0");// 不然,k输出了,a这个0就不用再输出了
	}
	else {
		if (num.k) printf(" ");
		printf("%lld", num.a);
		if (num.b != 1) printf("/%lld", num.b);
	}
	if (num.k < 0 || (num.k == 0 && f == -1)) printf(")");//同理要特判真分数是负的
}
void OutAll(Rnum  n1, Rnum n2, Rnum n3, char c) {//输出一个等式
	Outone(n1);
	printf(" %c ", c);
	Outone(n2);
	printf(" = ");
	if (c == '/' && n3.b == 0) printf("Inf");//分母为0特判
	else Outone(n3);
	printf("\n");
}
void Calculate(Rnum n1, Rnum n2) {//这就没什么了,四则运算的分子分母你肯定会算的
	Rnum n3;
	//加法
	n3.a = n1.a * n2.b + n2.a * n1.b;
	n3.b = n1.b * n2.b;
	OutAll(n1, n2, n3, '+');
	//减法
	n3.a = n1.a * n2.b - n2.a * n1.b;
	OutAll(n1, n2, n3, '-');
	//乘法
	n3.a = n1.a * n2.a;
	n3.b = n1.b * n2.b;
	OutAll(n1, n2, n3, '*');
	//除法
	n3.a = n1.a * n2.b;
	n3.b = n1.b * n2.a;
	OutAll(n1, n2, n3, '/');
}

加油!!!欢迎交流哦!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值