Program Listing for File fractions-new.hpp¶
↰ Return to documentation for file (py2cpp/fractions-new.hpp)
// The template and inlines for the -*- C++ -*- fraction classes.
// Initially implemented by Wai-Shing Luk <luk036@gmail.com>
//
#pragma once
#include <cmath>
#include <numeric>
#include <type_traits>
namespace fun
{
template <typename _Mn>
constexpr _Mn gcd(_Mn __m, _Mn __n)
{
return __m == 0 ? abs(__n) : __n == 0 ? abs(__m) : gcd(__n, __m % __n);
}
template <typename _Mn>
constexpr _Mn lcm(_Mn __m, _Mn __n)
{
return (__m != 0 and __n != 0) ? (abs(__m) / gcd(__m, __n)) * abs(__n) : 0;
}
template <typename Z>
struct Fraction
{
using _Self = Fraction<Z>;
Z _numerator;
Z _denominator;
constexpr Fraction(const Z& numerator, const Z& denominator)
{
const Z& common = gcd(numerator, denominator);
_numerator = (common == Z(0)) ? Z(0) : numerator / common;
_denominator = (common == Z(0)) ? Z(0) : denominator / common;
}
constexpr explicit Fraction(const Z& numerator)
: _numerator {numerator}
, _denominator {1}
{
}
constexpr Fraction() = default;
// Fraction(const _Self &) = delete;
// Fraction(_Self &&) = default;
constexpr const Z& numerator() const
{
return _numerator;
}
constexpr const Z& denominator() const
{
return _denominator;
}
constexpr _Self abs() const
{
return _Self(std::abs(_numerator), std::abs(_denominator));
}
constexpr void reciprocal()
{
std::swap(_numerator, _denominator);
}
constexpr _Self operator-() const
{
return _Self(-_numerator, _denominator);
}
constexpr _Self operator+(const _Self& frac) const
{
if (_denominator == frac._denominator)
{
return _Self(_numerator + frac._numerator, _denominator);
}
const auto common = lcm(_denominator, frac._denominator);
const auto n = common / _denominator * _numerator +
common / frac._denominator * frac._numerator;
return _Self(n, common);
}
constexpr _Self operator-(const _Self& frac) const
{
return *this + (-frac);
}
constexpr _Self operator*(const _Self& frac) const
{
const auto n = _numerator * frac._numerator;
const auto d = _denominator * frac._denominator;
return _Self(n, d);
}
constexpr _Self operator/(_Self frac) const
{
frac.reciprocal();
return *this * frac;
}
constexpr _Self operator+(const Z& i) const
{
const auto n = _numerator + _denominator * i;
return _Self(n, _denominator);
}
constexpr _Self operator-(const Z& i) const
{
return *this + (-i);
}
constexpr _Self operator*(const Z& i) const
{
const auto n = _numerator * i;
return _Self(n, _denominator);
}
constexpr _Self operator/(const Z& i) const
{
const auto d = _denominator * i;
return _Self(_numerator, d);
}
constexpr _Self operator+=(const _Self& frac)
{
return *this = *this + frac;
}
constexpr _Self operator-=(const _Self& frac)
{
return *this = *this - frac;
}
constexpr _Self operator*=(const _Self& frac)
{
return *this = *this * frac;
}
constexpr _Self operator/=(const _Self& frac)
{
return *this = *this / frac;
}
constexpr _Self operator+=(const Z& i)
{
return *this = *this + i;
}
constexpr _Self operator-=(const Z& i)
{
return *this = *this - i;
}
constexpr _Self operator*=(const Z& i)
{
return *this = *this * i;
}
constexpr _Self operator/=(const Z& i)
{
return *this = *this / i;
}
template <typename U>
constexpr auto cmp(const Fraction<U>& frac) const
{
// if (_denominator == frac._denominator) {
// return _numerator - frac._numerator;
// }
return _numerator * frac._denominator - _denominator * frac._numerator;
}
template <typename U>
constexpr bool operator==(const Fraction<U>& frac) const
{
if (_denominator == frac._denominator)
{
return _numerator == frac._numerator;
}
return this->cmp(frac) == 0;
}
template <typename U>
constexpr bool operator!=(const Fraction<U>& frac) const
{
return !(*this == frac);
}
template <typename U>
constexpr bool operator<(const Fraction<U>& frac) const
{
if (_denominator == frac._denominator)
{
return _numerator < frac._numerator;
}
return this->cmp(frac) < 0;
}
template <typename U>
constexpr bool operator>(const Fraction<U>& frac) const
{
return frac < *this;
}
template <typename U>
constexpr bool operator<=(const Fraction<U>& frac) const
{
return !(frac < *this);
}
template <typename U>
constexpr bool operator>=(const Fraction<U>& frac) const
{
return !(*this < frac);
}
constexpr auto cmp(const Z& c) const
{
return _numerator - _denominator * c;
}
constexpr bool operator==(const Z& c) const
{
return this->cmp(c) == 0;
}
constexpr bool operator!=(const Z& c) const
{
return this->cmp(c) != 0;
}
constexpr bool operator<(const Z& c) const
{
return this->cmp(c) < 0;
}
constexpr bool operator>(const Z& c) const
{
return this->cmp(c) > 0;
}
constexpr bool operator<=(const Z& c) const
{
return this->cmp(c) <= 0;
}
constexpr bool operator>=(const Z& c) const
{
return this->cmp(c) >= 0;
}
constexpr explicit operator double()
{
return double(_numerator) / _denominator;
}
friend constexpr _Self operator+(const Z& c, const _Self& frac)
{
return frac + c;
}
friend constexpr _Self operator-(const Z& c, const _Self& frac)
{
return (-frac) + c;
}
friend constexpr _Self operator*(const Z& c, const _Self& frac)
{
return frac * c;
}
friend constexpr _Self operator+(int&& c, const _Self& frac)
{
return frac + c;
}
friend constexpr _Self operator-(int&& c, const _Self& frac)
{
return (-frac) + c;
}
friend constexpr _Self operator*(int&& c, const _Self& frac)
{
return frac * c;
}
template <typename _Stream>
friend _Stream& operator<<(_Stream& os, const _Self& frac)
{
os << frac.numerator() << "/" << frac.denominator();
return os;
}
};
// For template deduction
// typename{Z} Fraction(const Z &, const Z &)->Fraction<Z>;
} // namespace fun