195 lines
5.1 KiB
C++
195 lines
5.1 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <numeric>
|
|
#include <ostream>
|
|
|
|
class Rational
|
|
{
|
|
public:
|
|
// Конструктор по умолчанию: 0/1
|
|
Rational() = default;
|
|
|
|
// Конструктор числителя
|
|
Rational(int numerator)
|
|
: numerator_{ numerator },
|
|
denominator_{ 1 } {
|
|
Reduction();
|
|
}
|
|
|
|
// Конструктор из числителя и знаменателя
|
|
Rational(int numerator, int denominator)
|
|
: numerator_{ numerator },
|
|
denominator_{ denominator } {
|
|
Reduction();
|
|
}
|
|
|
|
// Копирующий конструктор
|
|
Rational(const Rational& other)
|
|
: numerator_{other.numerator_},
|
|
denominator_(other.denominator_) {
|
|
}
|
|
|
|
// Возвращает обратную дробь
|
|
Rational Inv() const {
|
|
return Rational(denominator_, numerator_);
|
|
}
|
|
|
|
// Получить числитель
|
|
int GetNumerator() const {
|
|
return numerator_;
|
|
}
|
|
|
|
// Получить знаменатель
|
|
int GetDenominator() const {
|
|
return denominator_;
|
|
}
|
|
|
|
// Перегрузка оператора присваивания
|
|
Rational& operator=(const Rational&) = default;
|
|
|
|
// Унарный плюс
|
|
Rational operator+() const {
|
|
return *this;
|
|
return {numerator_, denominator_};
|
|
|
|
}
|
|
|
|
// Унарный минус
|
|
Rational operator-() const {
|
|
return Rational(-numerator_, denominator_);
|
|
}
|
|
|
|
// Сложение с присваиванием
|
|
Rational& operator+=(const Rational& other) {
|
|
numerator_ = numerator_ * other.denominator_ +
|
|
other.numerator_ * denominator_;
|
|
denominator_ = denominator_ * other.denominator_;
|
|
Reduction();
|
|
return *this;
|
|
}
|
|
|
|
// Вычитание с присваиванием
|
|
Rational& operator-=(const Rational& other) {
|
|
numerator_ = numerator_ * other.denominator_ -
|
|
other.numerator_ * denominator_;
|
|
denominator_ = denominator_ * other.denominator_;
|
|
Reduction();
|
|
return *this;
|
|
}
|
|
|
|
// Умножение с присваиванием
|
|
Rational& operator*=(const Rational& other) {
|
|
numerator_ = numerator_ * other.numerator_;
|
|
denominator_ = denominator_ * other.denominator_;
|
|
Reduction();
|
|
return *this;
|
|
}
|
|
|
|
// Деление с присваиванием
|
|
Rational& operator/=(const Rational& other) {
|
|
numerator_ *= other.denominator_;
|
|
denominator_ *= other.numerator_;
|
|
Reduction();
|
|
return *this;
|
|
}
|
|
|
|
// Сложение
|
|
Rational operator+(const Rational& other) const {
|
|
Rational result(*this);
|
|
result += other;
|
|
return result;
|
|
}
|
|
|
|
// Вычитание
|
|
Rational operator-(const Rational& other) const {
|
|
Rational result(*this);
|
|
result -= other;
|
|
return result;
|
|
}
|
|
|
|
// Умножение
|
|
Rational operator*(const Rational& other) const {
|
|
Rational result(*this);
|
|
result *= other;
|
|
return result;
|
|
}
|
|
|
|
// Деление
|
|
Rational operator/(const Rational& other) const {
|
|
Rational result(*this);
|
|
result /= other;
|
|
return result;
|
|
}
|
|
|
|
// Проверка равенства дробей
|
|
bool operator==(const Rational& other) const {
|
|
return static_cast<std::int64_t>(numerator_) * other.denominator_ ==
|
|
static_cast<std::int64_t>(other.numerator_) * denominator_;
|
|
}
|
|
|
|
// Трехстороннее сравнение
|
|
auto operator<=>(const Rational& other) const {
|
|
return static_cast<std::int64_t>(numerator_) * other.denominator_ <=>
|
|
static_cast<std::int64_t>(other.numerator_) * denominator_;
|
|
}
|
|
|
|
// Вывод дроби в поток
|
|
friend std::ostream& operator<<(std::ostream& os, const Rational& r) {
|
|
if (r.denominator_ == 1) {
|
|
os << r.numerator_;
|
|
} else {
|
|
os << r.numerator_ << " / " << r.denominator_;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
// Чтение дроби из потока
|
|
friend std::istream& operator>>(std::istream& is, Rational& r) {
|
|
int n;
|
|
int d;
|
|
char div;
|
|
|
|
is >> n;
|
|
if (!(is >> std::ws >> div)) {
|
|
r = Rational(n, 1);
|
|
return is;
|
|
}
|
|
|
|
if (div != '/') {
|
|
is.unget();
|
|
r = Rational(n, 1);
|
|
return is;
|
|
}
|
|
|
|
is >> d;
|
|
if (!is || d == 0) {
|
|
is.setstate(std::ios::failbit);
|
|
r = Rational(n, 1);
|
|
} else {
|
|
r = Rational(n, d);
|
|
}
|
|
return is;
|
|
}
|
|
|
|
private:
|
|
int numerator_ = 0;
|
|
int denominator_ = 1;
|
|
|
|
// Нормализация дроби
|
|
void Reduction() {
|
|
if (numerator_ == 0) {
|
|
denominator_ = 1;
|
|
return;
|
|
}
|
|
if (denominator_ < 0) {
|
|
numerator_ = -numerator_;
|
|
denominator_ = -denominator_;
|
|
}
|
|
const int divisor = std::gcd(numerator_, denominator_);
|
|
numerator_ /= divisor;
|
|
denominator_ /= divisor;
|
|
}
|
|
};
|