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