:github_url: https://github.com/svenevs/exhale-companion .. _program_listing_file_py2cpp_fractions-new.hpp: Program Listing for File fractions-new.hpp ========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``py2cpp/fractions-new.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // The template and inlines for the -*- C++ -*- fraction classes. // Initially implemented by Wai-Shing Luk // #pragma once #include #include #include namespace fun { template constexpr _Mn gcd(_Mn __m, _Mn __n) { return __m == 0 ? abs(__n) : __n == 0 ? abs(__m) : gcd(__n, __m % __n); } template constexpr _Mn lcm(_Mn __m, _Mn __n) { return (__m != 0 and __n != 0) ? (abs(__m) / gcd(__m, __n)) * abs(__n) : 0; } template struct Fraction { using _Self = Fraction; 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 constexpr auto cmp(const Fraction& frac) const { // if (_denominator == frac._denominator) { // return _numerator - frac._numerator; // } return _numerator * frac._denominator - _denominator * frac._numerator; } template constexpr bool operator==(const Fraction& frac) const { if (_denominator == frac._denominator) { return _numerator == frac._numerator; } return this->cmp(frac) == 0; } template constexpr bool operator!=(const Fraction& frac) const { return !(*this == frac); } template constexpr bool operator<(const Fraction& frac) const { if (_denominator == frac._denominator) { return _numerator < frac._numerator; } return this->cmp(frac) < 0; } template constexpr bool operator>(const Fraction& frac) const { return frac < *this; } template constexpr bool operator<=(const Fraction& frac) const { return !(frac < *this); } template constexpr bool operator>=(const Fraction& 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 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; } // namespace fun