【全网最细PAT题解】【PAT乙】1034 有理数四则运算

文章讲述了如何编写程序来计算两个有理数的加、减、乘、除,强调了输入输出格式、数据类型选择以及分数的最简形式和分母为零的特殊情况处理。解题策略包括使用longlong类型避免溢出,简化输出格式,以及在乘法和除法中进行约分操作。

题目链接

1034 有理数四则运算

题目描述

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

题目大意

给你两个分数,做四则运算

解题思路

科学计数法以后第二道恶心题,本题要注意的点非常多,当时题解也借鉴了柳婼大神的代码,下面我尽量将每一个要注意的点给读者剖析一下

  • 首先是范围问题,题目中说分子和分母全是整型范围内的整数,看似用int能满足,实则是不行的,因为会涉及到加法和乘法,所以我建议所有变量都用long long类型
  • 然后是输入问题scanf输入有一个很好的特点,是可以通过提前在""内定义不需要输入的数据,例如本题的输入,但是别忘了scanf输入是要带&
//直接将分数线 / 不存入,只保留两个数的分子分母
    scanf("%lld/%lld %lld/%lld",&a1,&b1,&a2,&b2);
  • 随后是分数的输出处理,我们可以看到,真的非常麻烦 ,在注释中也给出了比较详细的说明,读者可自行阅读
  • 然后是运算问题
    • 加减可以直接暴力求解,不会超过long long的范围
    • 乘法不行,需要先约分再运算,因为两个int最大值相乘long long还是顶不住
    • 除法注意判断分母为零的情况

题解

#include<bits/stdc++.h>
using namespace std;
void simp(long long a,long long b){
    //首先判断是不是分子是不是0,如果是的话直接输出0,就不用分数形式了
    if(a==0){
        cout<<"0";
        return;
    }
    bool f=false;       //用于判断是不是负数,ture代表是负数
    //主要用于判断后半边括号要不要输出

    if(a<0&&b>0||a>0&&b<0){
        //当分子分母符号不相同时,代表是负数
        cout<<"(-";     //输出负数的半边括号
        f=true;
    }

    //对ab取绝对值,便于后续的输出,因为已经判断好了符号了,就只需要单纯看数字怎么输出了
    a=abs(a);
    b=abs(b);
    //如果能被整除就代表输出形式不是分数而是整数了,直接return
    if(a%b==0){
        cout<<a/b;
        if(f)
            cout<<")";
        //是负数的话就输出后半边括号
        return;
    }
    //__gcd函数是用来求两个数的最大公约数的
    long long x=__gcd(a,b);

    //对分子分母约分
    a/=x;
    b/=x;

    //当分子小于分母(代表分数部分小于1),直接输出分数
    if(a<b){
        cout<<a<<"/"<<b;
    }
    //否则是带分数,需要输出 n又a分b几
    else{
        cout<<a/b<<" "<<a%b<<"/"<<b;
    }
    //输出后半边括号
    if(f){
        cout<<")";
    }
}

//加减都可以用最暴力的方法,因为不会超过long long的范围
void sum(long long a1,long long b1,long long a2,long long b2){
    simp(a1*b2+a2*b1,b1*b2);
}

//加减都可以用最暴力的方法,因为不会超过long long的范围
void sub(long long a1,long long b1,long long a2,long long b2){
    simp(a1*b2-a2*b1,b1*b2);
}

//乘法需要先约分在输出,不然两个int的最大值相乘还是顶不住范围
void mul(long long a1,long long b1,long long a2,long long b2){
    int x=__gcd(a1,b1);
    int y=__gcd(a2,b2);
    a1/=x;
    b1/=x;
    a2/=y;
    b2/=y;
    int x2=__gcd(a1,b2);
    int y2=__gcd(a2,b1);
    a1/=x2;
    b2/=x2;
    a2/=y2;
    b1/=y2;
    simp(a1*a2,b1*b2);
}

//除法需要额外判断两个分母为0的情况
void div(long long a1,long long b1,long long a2,long long b2){
    if(a1==0||a2==0){
        cout<<"Inf";
    }
    else{
        simp(a1*b2,a2*b1);
    }
}
int main(){
    long long a1,a2,b1,b2;
    //直接将分数线 / 不存入,只保留两个数的分子分母
    scanf("%lld/%lld %lld/%lld",&a1,&b1,&a2,&b2);
    simp(a1,b1); cout<<" + "; simp(a2,b2); cout<<" = "; sum(a1,b1,a2,b2); cout<<endl;
    simp(a1,b1); cout<<" - "; simp(a2,b2); cout<<" = "; sub(a1,b1,a2,b2); cout<<endl;
    simp(a1,b1); cout<<" * "; simp(a2,b2); cout<<" = "; mul(a1,b1,a2,b2); cout<<endl;
    simp(a1,b1); cout<<" / "; simp(a2,b2); cout<<" = "; div(a1,b1,a2,b2); cout<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值