[每日一题] 71. Rational Arithmetic(有理数类、重载)

1. 题目来源

链接:Rational Arithmetic (20)
来源:牛客网

2. 题目说明

For two rational numbers, your task is to implement the basic arithmetics, that is, to calculate their sum, difference,
product and quotient.

对于两个有理数,您的任务是实现基本算术,即计算它们的和,差,
乘积和商。

输入描述:

Each input file contains one test case, which gives in one line the two rational numbers in the format “a1/b1 a2/b2”.
The numerators and the denominators are all in the range of long int. If there is a negative sign, it must appear only in
front of the numerator. The denominators are guaranteed to be non-zero numbers.

每个输入文件包含一个测试用例,该测试用例在一行中以“ a1 / b1 a2 / b2”格式给出了两个有理数。
分子和分母都在long int范围内。如果有负号,则它只能出现在
分子前面。分母保证为非零数字。

输出描述:

For each test case, print in 4 lines the sum, difference, product and quotient of the two rational numbers, respectively. The format of each
line is “number1 operator number2 = result”. Notice that all the rational numbers must be in their simplest form “k a/b”, where k is
the integer part, and a/b is the simplest fraction part. If the number is negative, it must be included in a pair of parentheses. If the
denominator in the division is zero, output “Inf” as the result. It is guaranteed that all the output integers are in the range of long int.

对于每个测试用例,分别在4行中打印两个有理数的和,差,乘积和商。每
行的格式为“数字1运算符数字2 =结果”。请注意,所有有理数必须采用最简单的形式“ ka / b”,其中k是
整数部分,而a / b是最简单的分数部分。如果数字为负,则必须将其包含在一对括号中。如果
除法中的分母为零,则输出“ Inf”。确保所有输出整数都在long int范围内。

示例:

输入
5/3 0/6
输出
1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf

3. 题目解析

本题看上去不难,但是存在几个问题:
1)除数为0,这个很好解决,做个判断即可。
2)负数的输出,这个只要一个标签即可。
3)题目中虽然没有明说,但是这个数字处理后其实是有可能不存在分数部分或者整数部分的。也就是说将数据处理完形成k a/b的格式后,有可能只有一个k,也可能只有一个a/b,也有可能两者皆有,所以要分别考虑这几种情况。
可以尝试实现一个有理数类,将数据处理后重载一下加减乘除即可。处理数据的方法就是除一下mod一下的问题,加减乘除遵循基本的分数加减乘除原则,最后求一下最大公约数,做一下约分,再处理一下数据,就OK了。

4. 代码展示

#include <bits/stdc++.h>

using namespace std;

//long long是两个关键字拼起来的,用起来很不方便,重命名一下 
typedef long long _sint64;
//有理数类的声明 
class RationalNumber {
    bool m_infinate;        //处理除数为零 
    bool m_negative;        //处理负数 
    _sint64 m_numerator;    //分子,方便输出
    _sint64 m_denominator;  //分母 
    _sint64 m_integer;      //整数部分

    _sint64 m_numeratorAll; //记录无整数分数的分子,方便进行运算 
    _sint64 calcGCD(_sint64 a, _sint64 b); //求最大公约数的函数
    
public:
    RationalNumber(_sint64 numerator, _sint64 denominator); //构造函数
    RationalNumber operator+(RationalNumber const& o) const; //四则运算重载
    RationalNumber operator-(RationalNumber const& o) const;
    RationalNumber operator*(RationalNumber const& o) const;
    RationalNumber operator/(RationalNumber const& o) const;

    //输出流运算符重载
    friend std::ostream &operator<<(std::ostream &os, RationalNumber const& o);
};

//有理数类每个方法的实现
_sint64 RationalNumber::calcGCD(_sint64 a, _sint64 b) {
    if (b == 0) {
        return a;
    }

    //辗转相除法
    return calcGCD(b, a % b);
}

RationalNumber::RationalNumber(_sint64 numerator, _sint64 denominator) {
    m_negative = false;
    m_infinate = false;
    //处理分母为零的情况
    if (denominator == 0) {
        m_infinate = true;
        return;
    }

    //这里这样写,是因为在通过计算结果进行构造过程中,有可能出现分子分母均为负的情况。
    if (numerator < 0) {
        m_negative = !m_negative;
    }

    if (denominator < 0) {
        m_negative = !m_negative;
    }

    //计算整数、分子、分母。其中分母要参与下面的运算,所以不能是负的,用abs取绝对值,分子要保留原值
    m_integer = numerator / denominator;
      m_numerator = numerator - m_integer * denominator;
    m_denominator = abs(denominator);

    //约分,注意传给子函数的分子必须是正的,分母上面处理过了
    if (m_numerator) {
        _sint64 maxtmp = calcGCD(abs(m_numerator), m_denominator);

        if (maxtmp) {
            m_numerator /= maxtmp;
            m_denominator /= maxtmp;
        }
    }

    //计算约分后假分数版的分子,因为后续运算是不需要整数部分的,所以必须用假分数的分子算。
    m_numeratorAll = m_numerator + m_integer * m_denominator;
}

//以下为分数的加减乘除,统统使用m_numeratorAll(假分数的分子)进行运算。
RationalNumber RationalNumber::operator+(RationalNumber const& o) const {
    _sint64 numerator = (m_numeratorAll * o.m_denominator) +
                        (o.m_numeratorAll * m_denominator);
    _sint64 denominator = m_denominator * o.m_denominator;

    return RationalNumber(numerator, denominator);
}

RationalNumber RationalNumber::operator-(RationalNumber const& o) const {
    _sint64 numerator = (m_numeratorAll * o.m_denominator) -
                        (o.m_numeratorAll * m_denominator);
    _sint64 denominator = m_denominator * o.m_denominator;

    return RationalNumber(numerator, denominator);
}

RationalNumber RationalNumber::operator*(RationalNumber const& o) const {
    _sint64 numerator = m_numeratorAll * o.m_numeratorAll;
    _sint64 denominator = m_denominator * o.m_denominator;

    return RationalNumber(numerator, denominator);
}

RationalNumber RationalNumber::operator/(RationalNumber const& o) const {
    _sint64 numerator = m_numeratorAll * o.m_denominator;
    _sint64 denominator = m_denominator * o.m_numeratorAll;

    return RationalNumber(numerator, denominator);
}

std::ostream &operator<<(std::ostream &os, RationalNumber const& o) {
    //分母为0的情况就不用继续了
    if (o.m_infinate) {
        os << "Inf";
        return os;
    }

    //整数和分子为0那干脆就是0了
    if (o.m_numerator == 0 && o.m_integer == 0) {
        os << "0";
        return os;
    }

    //负数打印括号和负号
    if (o.m_negative) {
        os << "(-";
    }

    //有整数就打整数
    if (o.m_integer) {
        os << abs(o.m_integer);
        if (o.m_numerator) {  //整数小数都有就打个空格隔开
            os << " ";
        }
    }

    //有分数就打分数,分母已经abs过了,这里可以不用
    if (o.m_numerator) {
        os << abs(o.m_numerator) << '/' << o.m_denominator;
    }

    //负数的后半边括号
    if (o.m_negative) {
        os << ")";
    }

    return os;
}

int main() {
    _sint64 n1, d1, n2, d2;
    scanf("%lld/%lld %lld/%lld", &n1, &d1, &n2, &d2);
    RationalNumber rn1(n1, d1), rn2(n2, d2);

    //轻松+愉快的使用函数时间
    std::cout << rn1 << " + " << rn2 << " = " << rn1 + rn2 << '\n';
    std::cout << rn1 << " - " << rn2 << " = " << rn1 - rn2 << '\n';
    std::cout << rn1 << " * " << rn2 << " = " << rn1 * rn2 << '\n';
    std::cout << rn1 << " / " << rn2 << " = " << rn1 / rn2 << '\n';

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
有理数)创建一个名为 Rational,用于对分数进行算术运算。编写一个程序来测试你的。使用整数变量来表示的私有实例变量——分子和分母。 提供一个构造函数,使该的对象能够在声明时进行初始化。构造函数应以简化形式存储分数。分数 2/4 等价于 1/2,并将作为分子中的 1 和分母中的 2 存储在对象中。 如果没有提供初始值设定项,请提供默认值为 1 的无参数构造函数。 提供执行以下每个操作的公共方法: a) 将两个有理数相加:相加的结果应以简化形式存储。 b) 两个有理数相减:相减的结果应以简化形式存储。 c) 将两个有理数相乘:相乘的结果应以简化形式存储。 d) 将两个有理数相除:相除的结果应以简化形式存储。 e) 以 a/b 的形式返回有理数的字符串表示形式,其中 a 是分子,b 是分母。 f) 以浮点格式返回有理数的字符串表示形式. (考虑提供格式化功能,的用户能够指定小数点右侧的精度位数。) 【Sample output 1】 Enter numerator 1: 12 Enter denominator 1: 3 Enter numerator 2: 5 Enter denominator 2: 14 Enter precision: 3 a=4/1 b=5/14 a + b = 61/14 = 4.357 a - b = 51/14 = 3.643 a * b = 10/7 = 1.429 a / b = 56/5 = 11.200 【Sample output 2】 Enter numerator 1: 1 Enter denominator 1: 4 Enter numerator 2: 75 Enter denominator 2: 35 Enter precision: 1 a=1/4 b=15/7 a + b = 67/28 = 2.4 a - b = -53/28 = -1.9 a * b = 15/28 = 0.5 a / b = 7/60 = 0.1 Note: The red texts are inputed ,others are output texts. Just use a space to seperate words

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值