PAT乙级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
结尾无空行

解题思路

  1. 读入给定分数;
  2. 求解分母的最小公倍数;
  3. for循环进行加减乘除,对于每一种运算产生的运算结果和所使用的给定分数进行相同的“简化+格式化”输出(重复多次使用相同功能->调用函数);

难点

测试点2、3——测试点2答案错误,测试点3运行超时。
测试点2的解决:将所写的分式化简并输出的"simplify函数"中,判断分式符号的语句,由

if (a*b<0)

修改为

if ((a*1.0/b)<0)

这样可以避免a和b的积过大,超过了long int能够存储的范围而产生的错误,且乘法和除法在此所起到的功能相同。

测试点3的解决:将求解最大公因数的方法进行改变。由以下代码片的for遍历寻找的方法

    long int i;
    for (i=min(a,b);i>0;i--)
        if (a%i==0 && b%i==0)
            return i;

改为欧几里德算法(也叫辗转相除法)

long int y = a%b;
while (y!=0)
{
    a = b;
    b = y;
    y = a%b;
}
return b;

代码

#include<stdio.h>
#include<math.h>
long int min(long int a, long int b)
{
    if (a<b)
        return a;
    else
        return b;
}

long int GCD(long int a, long int b)//最大公约数
{
    long int y = a%b;
    while (y!=0)
    {
        a = b;
        b = y;
        y = a%b;
    }
    return b;
}

long int LCM(long int a, long int b)//最小公倍数
{
    long int c = GCD(a,b);
    return (a*b/c);
}

void simplify(long int a, long int b)//化简分式并按照格式输出
{
    int isNegative = 0;
    long int zs;
    if (b==0)
        printf("Inf");
    else if (a==0)
        printf("0");
    else //分母不是0
    {
        if ((a*1.0/b)<0)//将a*b修改为了a*1.0/b判断符号,因为前者可能超过long int的范围
            isNegative = 1;
        a = abs(a);
        b = abs(b);
        zs = a/b;
        a%=b;
        if (a!=0)
        {
            long int gcd = GCD(a,b);
            a/=gcd;
            b/=gcd;
        }
        if (isNegative==1)
        {
            printf("(-");
            if (zs!=0)
            {
                printf("%ld",zs);
                if (a!=0)
                    printf(" %ld/%ld)",a,b);
                else
                    printf(")");
            }
            else
                printf("%ld/%ld)",a,b);
        }
        else
        {
            if (zs!=0)
            {
                printf("%ld",zs);
                if (a!=0)
                    printf(" %ld/%ld",a,b);
            }
            else
                printf("%ld/%ld",a,b);
        }
    }
}

int main(){
    int i;
    long int fenzi[2],fenmu[2];//分子和分母全是整型范围内的整数
         //这里写为long int是防止计算时相乘后长于long int的结果被存入int,造成错误
    long int gbs,bs0,bs1;
    char symbol[4] = {'+','-','*','/'};
    scanf("%ld/%ld %ld/%ld",&fenzi[0],&fenmu[0],&fenzi[1],&fenmu[1]);
    gbs = LCM(fenmu[0],fenmu[1]);
    bs0 = gbs/fenmu[0];
    bs1 = gbs/fenmu[1];
    for (i=0;i<4;i++)
    {
        simplify(fenzi[0],fenmu[0]);
        printf(" %c ",symbol[i]);
        simplify(fenzi[1],fenmu[1]);
        printf(" = ");
        switch (i)
        {
            case 0:simplify(fenzi[0]*bs0+fenzi[1]*bs1,gbs);printf("\n");break;
            case 1:simplify(fenzi[0]*bs0-fenzi[1]*bs1,gbs);printf("\n");break;
            case 2:simplify(fenzi[0]*fenzi[1],fenmu[0]*fenmu[1]);printf("\n");break;
            case 3:simplify(fenzi[0]*fenmu[1],fenzi[1]*fenmu[0]);printf("\n");break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值