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