31struct is_Rational : std::false_type {};
34struct is_Rational<
Rational<T>> : std::true_type {};
75using grid_number_t = std::conditional_t<std::signed_integral<rational_int_t<T>>,
86 if (k & 1) result *= base;
105template <
class Int =
int64_t>
110 bool normalized_ =
true;
123 static constexpr std::size_t heapReductionLimbs = 8;
135 static constexpr bool reductionUrgent(
const Int& n,
const Int& d) {
136 if constexpr (
requires { n.fitsInt64(); }) {
152 if (n.fitsInt128() && d.fitsInt128()) {
153 return !n.fitsInt64() || !d.fitsInt64();
155 return !n.fitsLimbs(heapReductionLimbs) || !d.fitsLimbs(heapReductionLimbs);
157 constexpr int half = pgl::detail::numeric_limits<Int>::digits / 2 - 1;
158 const Int limit = Int(1) << half;
159 return pgl::detail::abs(n) >= limit || d >= limit;
177 static constexpr bool comparisonNeedsReduction(
const Int& n,
const Int& d) {
178 if constexpr (
requires { n.fitsInt64(); }) {
181 return reductionUrgent(n, d);
195 constexpr bool storedInteger()
const {
198 if constexpr (
requires { den.isOne(); }) {
201 return den == Int(1);
209 constexpr void operandParts(Int& n, Int& d)
const {
212 if (!normalized_ && reductionUrgent(n, d)) {
213 const Int g = pgl::detail::gcd(pgl::detail::abs(n), d);
234 num = Int(n.numerator());
235 den = Int(n.denominator());
241 constexpr Rational(pgl::detail::extended_integral
auto n) : num(n), den(1) {}
258 template <std::same_as<Int> T>
259 requires(!pgl::detail::extended_integral<Int> && !std::floating_point<Int>
261 constexpr Rational(T n) : num(std::move(n)), den(1) {}
266 constexpr Rational(Int n, Int d,
bool normalized =
false)
267 : num(n), den(d), normalized_(normalized) {
277 if (den == 1) normalized_ =
true;
296 template<std::
floating_po
int Float>
298 int digits = pgl::detail::numeric_limits<Int>::digits > 0
299 ? std::min(pgl::detail::numeric_limits<Float>::digits,
300 pgl::detail::numeric_limits<Int>::digits / 2 - 4)
301 : pgl::detail::numeric_limits<Float>::digits) {
302 if (!std::isfinite(f)) {
303 throw std::domain_error(
"pgl::Rational: cannot construct from a non-finite floating-point value");
314 std::frexp(f, &exponent);
315 const int fractionBits = exponent > 0 ? digits - exponent : digits;
316 if (fractionBits <= 0) {
319 if constexpr (pgl::detail::numeric_limits<Int>::is_bounded) {
320 if (exponent > pgl::detail::numeric_limits<Int>::digits) {
321 throw std::overflow_error(
"pgl::Rational: floating-point value does not fit the integer type");
324 num = Int(std::trunc(f));
330 if constexpr (
requires(Int
x, Float g) {
x * g; }) {
331 bool negative =
false;
336 den = Int(1) << fractionBits;
341 num = Int(negative ? -den * f : den * f);
360 if (normalized_)
return num;
361 return num / pgl::detail::gcd(pgl::detail::abs(num), den);
366 if (normalized_)
return den;
367 return den / pgl::detail::gcd(pgl::detail::abs(num), den);
400 if (den == 1 || num == 1 || num == -1) {
404 Int g = pgl::detail::gcd(pgl::detail::abs(num), den);
426 return Rational(Int(0), Int(1),
true);
428 if (den == 1 || num == 1 || num == -1) {
431 const Int g = pgl::detail::gcd(pgl::detail::abs(num), den);
432 return Rational(num / g, den / g,
true);
459 if (!normalized_ && reductionUrgent(num, den)) {
475 if (!normalized_ && reductionUrgent(num, den)) {
490 return normalized_ ? den == Int(1) : num % den == Int(0);
494 explicit constexpr operator float()
const {
496 return static_cast<float>(num);
498 return static_cast<float>(num) /
static_cast<float>(den);
508 explicit constexpr operator double()
const {
510 return static_cast<double>(num);
512 return static_cast<double>(num) /
static_cast<double>(den);
516 explicit constexpr operator long double()
const {
518 return static_cast<long double>(num);
520 return static_cast<long double>(num) /
static_cast<long double>(den);
532 explicit constexpr operator int()
const {
534 return static_cast<int>(num);
536 return static_cast<int>(num / den);
541 explicit constexpr operator int64_t()
const {
543 return static_cast<int64_t
>(num);
545 return static_cast<int64_t
>(num / den);
553 explicit constexpr operator Int() const
554 requires(!std::same_as<Int,
int> && !std::same_as<Int, int64_t>) {
562 template <
class OtherInt>
587 template <std::
floating_po
int Float =
double>
589 using Double = pgl::detail::promoted_number_t<Float>;
591 Double result =
static_cast<Double
>(num) /
static_cast<Double
>(den);
592 Float flt_result =
static_cast<Float
>(result);
597 while (
static_cast<Double
>(flt_result) > result) {
598 flt_result = std::nextafter(flt_result, -pgl::detail::numeric_limits<Float>::infinity());
606 if (
static_cast<Double
>(flt_result) == result && (*this <=> flt_result) < 0) {
607 flt_result = std::nextafter(flt_result, -pgl::detail::numeric_limits<Float>::infinity());
633 template <std::
floating_po
int Float =
double>
635 using Double = pgl::detail::promoted_number_t<Float>;
637 Double result =
static_cast<Double
>(num) /
static_cast<Double
>(den);
638 Float flt_result =
static_cast<Float
>(result);
643 while (
static_cast<Double
>(flt_result) < result) {
644 flt_result = std::nextafter(flt_result, pgl::detail::numeric_limits<Float>::infinity());
649 if (
static_cast<Double
>(flt_result) == result && (*this <=> flt_result) > 0) {
650 flt_result = std::nextafter(flt_result, pgl::detail::numeric_limits<Float>::infinity());
663 return normalized_ || !reductionUrgent(num, den);
669 if (storedInteger() && r.storedInteger()) {
670 return Rational(num + r.num, den,
true);
673 const Int rd = den * r.den;
674 return Rational(num * r.den + r.num * den, rd, rd == 1);
677 operandParts(an, ad);
678 r.operandParts(bn, bd);
679 const Int rd = ad * bd;
680 return Rational(an * bd + bn * ad, rd, rd == 1);
686 if (storedInteger() && r.storedInteger()) {
687 return Rational(num - r.num, den,
true);
690 const Int rd = den * r.den;
691 return Rational(num * r.den - r.num * den, rd, rd == 1);
694 operandParts(an, ad);
695 r.operandParts(bn, bd);
696 const Int rd = ad * bd;
697 return Rational(an * bd - bn * ad, rd, rd == 1);
701 if (storedInteger() && r.storedInteger()) {
702 return Rational(num * r.num, den,
true);
705 const Int rd = den * r.den;
706 return Rational(num * r.num, rd, rd == 1);
709 operandParts(an, ad);
710 r.operandParts(bn, bd);
711 const Int rd = ad * bd;
712 return Rational(an * bn, rd, rd == 1);
719 return num < 0 ?
Rational(-den, -num, normalized_)
729 return Rational(-num, den, normalized_);
744 requires (pgl::detail::extended_integral<I> || std::same_as<I, Int>)
748 requires (pgl::detail::extended_integral<I> || std::same_as<I, Int>)
752 requires (pgl::detail::extended_integral<I> || std::same_as<I, Int>)
760 requires (pgl::detail::extended_integral<I> || std::same_as<I, Int>)
790 template <
class A,
class B>
791 static constexpr std::strong_ordering
compareValues(
const A& a,
const B& b) {
792 if constexpr (
requires {
793 { a <=> b } -> std::same_as<std::strong_ordering>;
798 return std::strong_ordering::less;
800 return std::strong_ordering::greater;
801 return std::strong_ordering::equal;
809 using Wide = pgl::detail::promoted_number_t<Int>;
816 if (storedInteger() && r.storedInteger()) {
819 if ((!normalized_ && comparisonNeedsReduction(num, den)) ||
820 (!r.normalized_ && comparisonNeedsReduction(r.num, r.den))) {
822 operandParts(an, ad);
823 r.operandParts(bn, bd);
824 return compareValues(
static_cast<Wide
>(an) * bd,
static_cast<Wide
>(bn) * ad);
827 static_cast<Wide
>(r.num) * den);
840 requires (!std::same_as<U, Int>)
842 using Common = std::common_type_t<Int, U>;
843 using Wide = pgl::detail::promoted_number_t<Common>;
847 const Wide lhs =
static_cast<Wide
>(num) *
static_cast<Wide
>(other.
denominator());
848 const Wide rhs =
static_cast<Wide
>(other.
numerator()) *
static_cast<Wide
>(den);
856 using Wide = pgl::detail::promoted_number_t<Int>;
857 if (storedInteger() && r.storedInteger()) {
862 if ((!normalized_ && comparisonNeedsReduction(num, den)) ||
863 (!r.normalized_ && comparisonNeedsReduction(r.num, r.den))) {
865 operandParts(an, ad);
866 r.operandParts(bn, bd);
867 return static_cast<Wide
>(an) * bd ==
static_cast<Wide
>(bn) * ad;
869 return static_cast<Wide
>(num) * r.den ==
static_cast<Wide
>(r.num) * den;
872 return !(*
this == r);
883 requires (!std::same_as<U, Int>)
906 template <std::
floating_po
int Float>
909 return std::partial_ordering::unordered;
911 return f > 0 ? std::partial_ordering::less
912 : std::partial_ordering::greater;
924 const Float frac = std::frexp(f, &exponent);
925 const int digits = pgl::detail::numeric_limits<Float>::digits;
927 const int E = exponent - digits;
936 rhs *= detail::pow2(E);
938 lhs *= detail::pow2(-E);
943 template <std::
floating_po
int Float>
945 return std::isfinite(f) &&
946 (*this <=> f) == std::partial_ordering::equivalent;
975 if constexpr (std::is_unsigned_v<I>) {
998 requires(pgl::detail::extended_integral<I> || std::same_as<I, Int>)
1000 using Wide = pgl::detail::promoted_number_t<Int>;
1008 if (den == 1)
return compareValues(num,
static_cast<Wide
>(n));
1016 if (!normalized_ && comparisonNeedsReduction(num, den)) {
1018 operandParts(an, ad);
1030 requires(pgl::detail::extended_integral<I> || std::same_as<I, Int>)
1031 constexpr bool operator==(
const I& n)
const {
1032 return (*this <=> n) == 0;
1047 if (reduced.den == 1)
1048 return os << reduced.num;
1050 return os << reduced.num <<
"/" << reduced.den;
1060 if (!(is >> n))
return is;
1066 if (is.peek() ==
'/') {
1068 }
else if (is.fail()) {
1069 is.clear(is.rdstate() & ~std::ios::failbit);
1093 requires(!pgl::detail::extended_integral<T> && !std::floating_point<T>
1094 && !RationalConcept<T>)
1108template <>
struct select_int_ge<8> {
using type = std::int8_t; };
1109template <>
struct select_int_ge<16> {
using type = std::int16_t; };
1110template <>
struct select_int_ge<32> {
using type = std::int32_t; };
1111template <>
struct select_int_ge<64> {
using type = std::int64_t; };
1112template <>
struct select_int_ge<128> {
using type =
pgl::int128; };
1116 if (bits <= 8)
return 8;
1117 if (bits <= 16)
return 16;
1118 if (bits <= 32)
return 32;
1119 if (bits <= 64)
return 64;
1123template <
typename T>
1124struct is_int128 : std::false_type {};
1126template <>
struct is_int128<pgl::
int128> : std::true_type {};
1127#ifdef __SIZEOF_INT128__
1128template <>
struct is_int128<__uint128_t> : std::true_type {};
1131template <
typename T>
1133 std::is_integral_v<T> ||
1134 std::is_floating_point_v<T> ||
1135 is_int128<T>::value;
1137template <NumericType T>
1138struct to_integer_with_digits {
1140 static constexpr int bits = pgl::detail::numeric_limits<T>::digits;
1144 using type =
typename select_int_ge<rounded>::type;
1147template <
typename T>
1164template <
class Number>
1174template <
class Number>
1179template<
class U,
class V>
1188template<
class U, std::
floating_po
int F>
1192template<std::
floating_po
int F,
class V>
1202 static constexpr bool is_specialized =
true;
1216 static constexpr int digits = pgl::detail::numeric_limits<Int>::digits;
1217 static constexpr int digits10 = pgl::detail::numeric_limits<Int>::digits10;
1219 static constexpr bool is_signed = pgl::detail::numeric_limits<Int>::is_signed;
1220 static constexpr bool is_integer =
false;
1221 static constexpr bool is_exact =
true;
1227 static constexpr int radix = 2;
1228 static constexpr int min_exponent = 0;
1229 static constexpr int min_exponent10 = 0;
1230 static constexpr int max_exponent = 0;
1231 static constexpr int max_exponent10 = 0;
1232 static constexpr bool is_bounded = pgl::detail::numeric_limits<Int>::is_bounded;
1233 static constexpr bool is_modulo =
false;
1234 static constexpr bool is_iec559 =
false;
1235 static constexpr bool has_infinity =
false;
1236 static constexpr bool has_quiet_NaN =
false;
1237 static constexpr bool has_signaling_NaN =
false;
1238 static constexpr bool traps =
false;
1239 static constexpr bool tinyness_before =
false;
1240 static constexpr std::float_round_style round_style = std::round_toward_zero;
Arbitrary precision signed integers, optimized for small values.
Arbitrary precision signed integer.
Definition bigint.hpp:157
Exact rational number class template.
Definition rational.hpp:106
constexpr Rational operator--(int)
Definition rational.hpp:1039
constexpr bool operator!=(const Rational &r) const
Definition rational.hpp:871
static constexpr std::strong_ordering compareValues(const A &a, const B &b)
Three-way ordering of two values.
Definition rational.hpp:791
constexpr Rational(Int n, Int d, bool normalized=false)
Construct from numerator and denominator.
Definition rational.hpp:266
constexpr Float lowerBound() const
Computes a monotone, downward-rounded floating-point approximation of num / den.
Definition rational.hpp:588
constexpr Rational< Int > operator*(const Rational< Int > &r) const
Definition rational.hpp:700
constexpr Rational(RationalConcept auto n)
Construct from another Rational.
Definition rational.hpp:232
constexpr Int numerator() const noexcept
Get numerator (in lowest terms).
Definition rational.hpp:359
constexpr Rational & operator+=(const Rational &r)
Definition rational.hpp:733
constexpr void simplify()
Reduces the stored fraction to lowest terms in place (den stays > 0).
Definition rational.hpp:388
constexpr bool safeRaw() const
Whether the raw num/den can be combined as-is without first reducing (i.e. already normalized,...
Definition rational.hpp:662
friend constexpr Rational operator-(Int x, const Rational &r)
Definition rational.hpp:768
constexpr Rational reciprocal() const
Definition rational.hpp:715
constexpr Rational & operator--()
Definition rational.hpp:1038
constexpr Float upperBound() const
Computes a monotone, upward-rounded floating-point approximation of num / den.
Definition rational.hpp:634
constexpr Rational & operator/=(const Rational &r)
Definition rational.hpp:736
constexpr Rational operator-(const Rational &r) const
Definition rational.hpp:683
constexpr Rational(Float f, int digits=pgl::detail::numeric_limits< Int >::digits > 0 ? std::min(pgl::detail::numeric_limits< Float >::digits, pgl::detail::numeric_limits< Int >::digits/2 - 4) :pgl::detail::numeric_limits< Float >::digits)
Construct from floating point.
Definition rational.hpp:297
friend std::ostream & operator<<(std::ostream &os, const Rational &r)
Output format: num/den or just num if den==1.
Definition rational.hpp:1044
constexpr Int denominator() const noexcept
Get denominator (in lowest terms).
Definition rational.hpp:365
constexpr std::strong_ordering operator<=>(const Rational &r) const
Three-way comparison operator.
Definition rational.hpp:808
constexpr Rational operator+(const Rational &r) const
Definition rational.hpp:666
constexpr Rational & operator-=(const Rational &r)
Definition rational.hpp:734
std::partial_ordering operator<=>(Float f) const
Exact three-way comparison against a floating-point value (partial: NaN compares unordered).
Definition rational.hpp:907
friend std::istream & operator>>(std::istream &is, Rational &r)
Input format: num/den or integer.
Definition rational.hpp:1056
constexpr Rational(T n)
Construct from a numerator of the rational's own integer type (denominator 1), covering integer types...
Definition rational.hpp:261
constexpr Rational simplifiedIfLarge() const
Returns this value reduced, but only when it is already wide enough that the next arithmetic step wou...
Definition rational.hpp:474
constexpr Rational & operator*=(const Rational &r)
Definition rational.hpp:735
constexpr Rational operator-() const
Definition rational.hpp:727
constexpr Rational operator/(const Rational &r) const
Definition rational.hpp:723
constexpr Rational()
Default constructor (0).
Definition rational.hpp:223
static constexpr bool isNegativeOne(const I &n)
Whether an integer argument is exactly -1.
Definition rational.hpp:974
bool operator==(Float f) const
Exact equality against a floating-point value.
Definition rational.hpp:944
friend constexpr Rational operator/(Int x, const Rational &r)
Definition rational.hpp:770
constexpr Rational & operator++()
Definition rational.hpp:1035
constexpr Rational operator++(int)
Definition rational.hpp:1036
friend constexpr Rational operator*(Int x, const Rational &r)
Definition rational.hpp:769
constexpr void simplifyIfLarge()
Reduces in place, but only when the stored parts have already grown wide enough that the next arithme...
Definition rational.hpp:458
constexpr Rational(pgl::detail::extended_integral auto n)
Construct from integer.
Definition rational.hpp:241
constexpr Rational simplified() const
Returns this value reduced to lowest terms.
Definition rational.hpp:421
constexpr bool operator==(const Rational &r) const
Equality comparison.
Definition rational.hpp:855
friend constexpr Rational operator+(Int x, const Rational &r)
Definition rational.hpp:767
constexpr bool isInteger() const
Whether this rational is exactly an integer.
Definition rational.hpp:489
Definition rational.hpp:1132
Definition rational.hpp:40
Definition arrangement.hpp:67
constexpr int round_up_bits(int bits)
Definition rational.hpp:1115
@ x
Definition intervaltree.hpp:24
std::conditional_t< std::signed_integral< rational_int_t< T > >, rational_int_t< T >, std::int64_t > grid_number_t
The integer type a coordinate rasterizes onto by default.
Definition rational.hpp:75
constexpr bool is_Rational_v
Definition rational.hpp:37
typename DivisionResult< Number >::type division_result_t
Convenience alias for DivisionResult.
Definition rational.hpp:1175
Rational< BigInt > ERational
Exact, overflow-free result used when integral coordinates require fractions.
Definition rational.hpp:1151
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 127, 127, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void > > int128
Signed 128-bit integer.
Definition numeric.hpp:64
Rational(T) -> Rational< T >
typename rational_int< T >::type rational_int_t
Definition rational.hpp:61
typename to_integer_with_digits< T >::type to_integer_with_digits_t
Definition rational.hpp:1148
Default result type for an operation that may require division.
Definition rational.hpp:1165
std::conditional_t< std::floating_point< NumberType >||RationalConcept< NumberType >, NumberType, ERational > type
Definition rational.hpp:1167
std::remove_cvref_t< Number > NumberType
Definition rational.hpp:1166
Int type
Definition rational.hpp:57
The integer type a Rational stores its parts in; any other type is its own answer.
Definition rational.hpp:51
T type
Definition rational.hpp:52