This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub suisen-cp/cp-library-cpp
#include "library/number/rational.hpp"
#ifndef SUISEN_RATIONAL #define SUISEN_RATIONAL #include <cmath> #include <ostream> #include <numeric> #include <type_traits> #include <vector> namespace suisen { template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr> struct Rational { T num, den; Rational() : Rational(0) {} Rational(T n) : num(n), den(1) {} Rational(T n, T d) { if (n == 0) { assert(d != 0); num = 0, den = 1; } else { T g = std::gcd(n, d); n /= g, d /= g; if (d < 0) n = -n, d = -d; num = n, den = d; } } // l > 0 -> 1, l = 0 -> 0, l < 0 -> -1 int signum() const { return -1 + (num >= 0) + (num > 0); } // l > r -> 1, l = r -> 0, l < r -> -1 static int compare(const Rational &l, const Rational &r) { auto pow_m1 = [](bool x) { return -int(x) | 1; }; const int sgn_l = l.signum(), sgn_r = r.signum(); if (l.num == 0) return -sgn_r; if (r.num == 0) return +sgn_l; if ((sgn_l ^ sgn_r) < 0) return sgn_l; T nl = std::abs(l.num), dl = l.den, nr = std::abs(r.num), dr = r.den; bool rev = sgn_l < 0; for (; dl and dr; rev = -rev) { T ql = nl / dl, qr = nr / dr; if (ql != qr) return pow_m1((ql < qr) xor rev); T rl = nl % dl, rr = nr % dr; nl = dl, dl = rl; nr = dr, dr = rr; } return dl or dr ? pow_m1((dr > 0) xor rev) : 0; } friend bool operator<(const Rational &l, const Rational &r) { return compare(l, r) < 0; } friend bool operator>(const Rational &l, const Rational &r) { return compare(l, r) > 0; } friend bool operator<=(const Rational &l, const Rational &r) { return compare(l, r) <= 0; } friend bool operator>=(const Rational &l, const Rational &r) { return compare(l, r) >= 0; } friend bool operator==(const Rational &l, const Rational &r) { return compare(l, r) == 0; } friend bool operator!=(const Rational &l, const Rational &r) { return compare(l, r) != 0; } Rational operator+() const { return *this; } Rational operator-() const { return Rational(-num, den); } friend Rational operator+(const Rational &l, const Rational &r) { T lcm = l.den / std::gcd(l.den, r.den) * r.den; return Rational(l.num * (lcm / l.den) + r.num * (lcm / r.den), lcm); } friend Rational operator-(const Rational &l, const Rational &r) { T lcm = l.den / std::gcd(l.den, r.den) * r.den; return Rational(l.num * (lcm / l.den) - r.num * (lcm / r.den), lcm); } friend Rational operator*(const Rational &l, const Rational &r) { T g1 = std::gcd(l.num, r.den); T g2 = std::gcd(l.den, r.num); return Rational((l.num / g1) * (r.num / g2), (l.den / g2) * (r.den / g1)); } friend Rational operator/(const Rational &l, const Rational &r) { return l * r.inv(); } Rational& operator+=(const Rational &r) { *this = *this + r; return *this; } Rational& operator-=(const Rational &r) { *this = *this - r; return *this; } Rational& operator*=(const Rational &r) { *this = *this * r; return *this; } Rational& operator/=(const Rational &r) { *this = *this / r; return *this; } Rational inv() const { return Rational(den, num); } Rational abs() const { return Rational(std::abs(num), den); } explicit operator int() const { return (int) (num / den); } explicit operator long long() const { return (long long) (num / den); } explicit operator double() const { return (double) num / den; } explicit operator long double() const { return (long double) num / den; } T floor() const { return num >= 0 ? num / den : -(-num / den); } T ceil() const { return num >= 0 ? -(-num / den) : num / den; } static std::pair<Rational, Rational> approximate(long double target, T max_numerator, T max_denominator) { long double x = std::abs(target); T nl = 0, dl = 1, nr = 1, dr = 0; while (true) { T nm = nl + nr, dm = dl + dr; if (nm > max_numerator or dm > max_denominator) break; if ((long double) nm / dm < x) { nl = nm, dl = dm; } else { nr = nm, dr = dm; } } if (target >= 0) { return { Rational(+nl, dl), Rational(+nr, dr) }; } else { return { Rational(-nr, dr), Rational(-nl, dl) }; } } static std::vector<Rational> stern_brocot(int depth) { std::vector<Rational> t(1 << (depth + 1)); for (int i = 1; i < int(t.size()); ++i) { int lk, rk; if (i & 1) { lk = i >> 1, rk = i >> (__builtin_ctz(~i) + 1); } else { rk = i >> 1, lk = i >> (__builtin_ctz( i) + 1); } Rational lr = lk == 0 ? Rational(0, 1) : t[lk]; Rational rr = rk == 0 ? Rational(1, 0) : t[rk]; t[i] = Rational(lr.num + rr.num, lr.den + rr.den); } return t; } static std::vector<Rational> farey_sequence(int depth) { const int n = 1 << (depth + 1); std::vector<Rational> t(n); for (int i = 1; i < n; i++) { int lk, rk; if (i & 1) { lk = i >> 1, rk = i >> (__builtin_ctz(~i) + 1); } else { rk = i >> 1, lk = i >> (__builtin_ctz( i) + 1); } Rational lr = lk == 0 ? Rational(0, 1) : t[lk]; Rational rr = rk == 0 ? Rational(1, 1) : t[rk]; t[i] = Rational(lr.num + rr.num, lr.den + rr.den); } std::vector<Rational> seq(n + 1); int i = 0; auto dfs = [&](auto dfs, int k) -> void { if (k >= n) return; dfs(dfs, k * 2 + 0); seq[i++] = t[k]; dfs(dfs, k * 2 + 1); }; seq[i++] = Rational(0, 1); dfs(dfs, 1); seq[i++] = Rational(1, 1); return seq; } }; } template <typename T> std::ostream& operator<<(std::ostream &out, const suisen::Rational<T> &r) { return out << r.num << '/' << r.den; } template <typename T> suisen::Rational<T> max(const suisen::Rational<T> &l, const suisen::Rational<T> &r) { return l > r ? l : r; } template <typename T> suisen::Rational<T> min(const suisen::Rational<T> &l, const suisen::Rational<T> &r) { return l < r ? l : r; } #endif // SUISEN_RATIONAL
#line 1 "library/number/rational.hpp" #include <cmath> #include <ostream> #include <numeric> #include <type_traits> #include <vector> namespace suisen { template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr> struct Rational { T num, den; Rational() : Rational(0) {} Rational(T n) : num(n), den(1) {} Rational(T n, T d) { if (n == 0) { assert(d != 0); num = 0, den = 1; } else { T g = std::gcd(n, d); n /= g, d /= g; if (d < 0) n = -n, d = -d; num = n, den = d; } } // l > 0 -> 1, l = 0 -> 0, l < 0 -> -1 int signum() const { return -1 + (num >= 0) + (num > 0); } // l > r -> 1, l = r -> 0, l < r -> -1 static int compare(const Rational &l, const Rational &r) { auto pow_m1 = [](bool x) { return -int(x) | 1; }; const int sgn_l = l.signum(), sgn_r = r.signum(); if (l.num == 0) return -sgn_r; if (r.num == 0) return +sgn_l; if ((sgn_l ^ sgn_r) < 0) return sgn_l; T nl = std::abs(l.num), dl = l.den, nr = std::abs(r.num), dr = r.den; bool rev = sgn_l < 0; for (; dl and dr; rev = -rev) { T ql = nl / dl, qr = nr / dr; if (ql != qr) return pow_m1((ql < qr) xor rev); T rl = nl % dl, rr = nr % dr; nl = dl, dl = rl; nr = dr, dr = rr; } return dl or dr ? pow_m1((dr > 0) xor rev) : 0; } friend bool operator<(const Rational &l, const Rational &r) { return compare(l, r) < 0; } friend bool operator>(const Rational &l, const Rational &r) { return compare(l, r) > 0; } friend bool operator<=(const Rational &l, const Rational &r) { return compare(l, r) <= 0; } friend bool operator>=(const Rational &l, const Rational &r) { return compare(l, r) >= 0; } friend bool operator==(const Rational &l, const Rational &r) { return compare(l, r) == 0; } friend bool operator!=(const Rational &l, const Rational &r) { return compare(l, r) != 0; } Rational operator+() const { return *this; } Rational operator-() const { return Rational(-num, den); } friend Rational operator+(const Rational &l, const Rational &r) { T lcm = l.den / std::gcd(l.den, r.den) * r.den; return Rational(l.num * (lcm / l.den) + r.num * (lcm / r.den), lcm); } friend Rational operator-(const Rational &l, const Rational &r) { T lcm = l.den / std::gcd(l.den, r.den) * r.den; return Rational(l.num * (lcm / l.den) - r.num * (lcm / r.den), lcm); } friend Rational operator*(const Rational &l, const Rational &r) { T g1 = std::gcd(l.num, r.den); T g2 = std::gcd(l.den, r.num); return Rational((l.num / g1) * (r.num / g2), (l.den / g2) * (r.den / g1)); } friend Rational operator/(const Rational &l, const Rational &r) { return l * r.inv(); } Rational& operator+=(const Rational &r) { *this = *this + r; return *this; } Rational& operator-=(const Rational &r) { *this = *this - r; return *this; } Rational& operator*=(const Rational &r) { *this = *this * r; return *this; } Rational& operator/=(const Rational &r) { *this = *this / r; return *this; } Rational inv() const { return Rational(den, num); } Rational abs() const { return Rational(std::abs(num), den); } explicit operator int() const { return (int) (num / den); } explicit operator long long() const { return (long long) (num / den); } explicit operator double() const { return (double) num / den; } explicit operator long double() const { return (long double) num / den; } T floor() const { return num >= 0 ? num / den : -(-num / den); } T ceil() const { return num >= 0 ? -(-num / den) : num / den; } static std::pair<Rational, Rational> approximate(long double target, T max_numerator, T max_denominator) { long double x = std::abs(target); T nl = 0, dl = 1, nr = 1, dr = 0; while (true) { T nm = nl + nr, dm = dl + dr; if (nm > max_numerator or dm > max_denominator) break; if ((long double) nm / dm < x) { nl = nm, dl = dm; } else { nr = nm, dr = dm; } } if (target >= 0) { return { Rational(+nl, dl), Rational(+nr, dr) }; } else { return { Rational(-nr, dr), Rational(-nl, dl) }; } } static std::vector<Rational> stern_brocot(int depth) { std::vector<Rational> t(1 << (depth + 1)); for (int i = 1; i < int(t.size()); ++i) { int lk, rk; if (i & 1) { lk = i >> 1, rk = i >> (__builtin_ctz(~i) + 1); } else { rk = i >> 1, lk = i >> (__builtin_ctz( i) + 1); } Rational lr = lk == 0 ? Rational(0, 1) : t[lk]; Rational rr = rk == 0 ? Rational(1, 0) : t[rk]; t[i] = Rational(lr.num + rr.num, lr.den + rr.den); } return t; } static std::vector<Rational> farey_sequence(int depth) { const int n = 1 << (depth + 1); std::vector<Rational> t(n); for (int i = 1; i < n; i++) { int lk, rk; if (i & 1) { lk = i >> 1, rk = i >> (__builtin_ctz(~i) + 1); } else { rk = i >> 1, lk = i >> (__builtin_ctz( i) + 1); } Rational lr = lk == 0 ? Rational(0, 1) : t[lk]; Rational rr = rk == 0 ? Rational(1, 1) : t[rk]; t[i] = Rational(lr.num + rr.num, lr.den + rr.den); } std::vector<Rational> seq(n + 1); int i = 0; auto dfs = [&](auto dfs, int k) -> void { if (k >= n) return; dfs(dfs, k * 2 + 0); seq[i++] = t[k]; dfs(dfs, k * 2 + 1); }; seq[i++] = Rational(0, 1); dfs(dfs, 1); seq[i++] = Rational(1, 1); return seq; } }; } template <typename T> std::ostream& operator<<(std::ostream &out, const suisen::Rational<T> &r) { return out << r.num << '/' << r.den; } template <typename T> suisen::Rational<T> max(const suisen::Rational<T> &l, const suisen::Rational<T> &r) { return l > r ? l : r; } template <typename T> suisen::Rational<T> min(const suisen::Rational<T> &l, const suisen::Rational<T> &r) { return l < r ? l : r; }