38#if defined(__GNUC__) || defined(__clang__)
39#define PGL_BIGINT_COLD [[gnu::noinline, gnu::cold]]
41#define PGL_BIGINT_COLD
66 std::size_t count()
const {
return static_cast<std::size_t
>(data_[-1]); }
68 void allocate(std::size_t n) {
74 void copyFrom(
const pgl::int128* src, std::size_t n) {
76 for (std::size_t i = 0; i < n; ++i) {
89 LimbStore() =
default;
90 LimbStore(
const LimbStore& o) {
92 copyFrom(o.data_, o.count());
95 LimbStore(LimbStore&& o) noexcept : data_(o.data_) { o.data_ =
nullptr; }
96 LimbStore& operator=(
const LimbStore& o) {
100 copyFrom(o.data_, o.count());
105 LimbStore& operator=(LimbStore&& o)
noexcept {
113 ~LimbStore() { release(); }
116 LimbStore& operator=(
const std::vector<pgl::int128>& v) {
119 copyFrom(v.data(), v.size());
124 bool empty()
const {
return data_ ==
nullptr; }
125 std::size_t size()
const {
return data_ ? count() : 0; }
126 pgl::int128& operator[](std::size_t i) {
return data_[i]; }
127 const pgl::int128& operator[](std::size_t i)
const {
return data_[i]; }
129 const pgl::int128* end()
const {
return data_ ? data_ + count() :
nullptr; }
130 void clear() { release(); }
137 for (std::size_t i = 0; i < n; ++i) {
168 detail::LimbStore limbs_;
169 bool negative_ =
false;
171 using Limbs = std::vector<pgl::int128>;
173 friend struct std::hash<
BigInt>;
176 static constexpr int kLimbBits = 62;
182 static pgl::int128 limbMask() {
return base() - 1; }
185 static pgl::int128 int128Max() {
return pgl::detail::numeric_limits<pgl::int128>::max(); }
190 static void trim(Limbs& v) {
191 while (!v.empty() && v.back() == 0) {
197 static int cmpMag(
const Limbs& a,
const Limbs& b) {
198 if (a.size() != b.size()) {
199 return a.size() < b.size() ? -1 : 1;
201 for (std::size_t i = a.size(); i-- > 0;) {
203 return a[i] < b[i] ? -1 : 1;
210 static Limbs addMag(
const Limbs& a,
const Limbs& b) {
212 const std::size_t n = a.size() < b.size() ? b.size() : a.size();
215 for (std::size_t i = 0; i < n; ++i) {
217 if (i < a.size()) sum += a[i];
218 if (i < b.size()) sum += b[i];
219 r.push_back(sum & limbMask());
220 carry = sum >> kLimbBits;
229 static void subMagInPlace(Limbs& a,
const Limbs& b) {
231 for (std::size_t i = 0; i < a.size(); ++i) {
245 static Limbs subMag(
const Limbs& a,
const Limbs& b) {
252 static void shiftLeftOneMag(Limbs& v) {
256 limb = ((limb << 1) & limbMask()) | carry;
265 static Limbs mulMag(
const Limbs& a,
const Limbs& b) {
266 if (a.empty() || b.empty()) {
270 for (std::size_t i = 0; i < a.size(); ++i) {
272 for (std::size_t j = 0; j < b.size(); ++j) {
274 r[i + j] = cur & limbMask();
275 carry = cur >> kLimbBits;
277 r[i + b.size()] += carry;
294 static std::size_t bitLengthMag(
const Limbs& v) {
298 return (v.size() - 1) * kLimbBits +
static_cast<std::size_t
>(topBit(v.back())) + 1;
302 static bool testBitMag(
const Limbs& v, std::size_t i) {
303 const std::size_t limb = i / kLimbBits;
304 const std::size_t off = i % kLimbBits;
305 if (limb >= v.size()) {
308 return ((v[limb] >>
static_cast<int>(off)) & 1) != 0;
319 static std::pair<Limbs, Limbs> divmodMag(
const Limbs& n,
const Limbs& d) {
320 if (cmpMag(n, d) < 0) {
327 for (std::size_t i = n.size(); i-- > 0;) {
329 const pgl::int128 current = (remainder << kLimbBits) | n[i];
330 q[i] = current / divisor;
331 remainder = current % divisor;
335 if (remainder != 0) {
336 r.push_back(remainder);
338 return {std::move(q), std::move(r)};
341 r.reserve(d.size() + 1);
342 for (std::size_t bit = bitLengthMag(n); bit-- > 0;) {
344 if (testBitMag(n, bit)) {
350 if (cmpMag(r, d) >= 0) {
352 q[bit / kLimbBits] |=
pgl::int128(1) <<
static_cast<int>(bit % kLimbBits);
357 return {std::move(q), std::move(r)};
363 Limbs magToLimbs()
const {
364 if (!limbs_.empty()) {
365 return Limbs(limbs_.begin(), limbs_.end());
370 v.push_back(
x & limbMask());
377 static bool limbsFitInt128(
const Limbs& v,
pgl::int128& out) {
380 for (std::size_t i = v.size(); i-- > 0;) {
381 if (acc > maxv / base()) {
385 if (acc > maxv - v[i]) {
396 void setFromLimbs(Limbs v,
bool neg) {
405 if (limbsFitInt128(v, fitted)) {
410 limbs_ = std::move(v);
418 b.small_ = magnitude;
419 b.negative_ = (magnitude != 0) && neg;
424 int compareMag(
const BigInt& o)
const {
425 if (limbs_.empty() && o.limbs_.empty()) {
426 if (small_ == o.small_)
return 0;
427 return small_ < o.small_ ? -1 : 1;
429 return compareMagGeneral(o);
436 int compareMagGeneral(
const BigInt& o)
const {
441 if (limbs_.empty()) {
444 if (o.limbs_.empty()) {
447 const std::size_t n = limbs_.size(), m = o.limbs_.size();
449 return n < m ? -1 : 1;
451 for (std::size_t i = n; i-- > 0;) {
452 if (limbs_[i] != o.limbs_[i]) {
453 return limbs_[i] < o.limbs_[i] ? -1 : 1;
460 std::string magToDecimalString()
const {
461 Limbs v = magToLimbs();
465 const Limbs divisor = {
pgl::int128(int64_t(1000000000000000000))};
466 std::vector<int64_t> chunks;
468 auto [quotient, remainder] = divmodMag(v, divisor);
469 chunks.push_back(remainder.empty() ? int64_t(0) :
static_cast<int64_t
>(remainder[0]));
470 v = std::move(quotient);
472 std::string s = std::to_string(chunks.back());
473 for (std::size_t i = chunks.size() - 1; i-- > 0;) {
474 std::string part = std::to_string(chunks[i]);
475 s += std::string(18 - part.size(),
'0');
487 Limbs av = a.magToLimbs();
488 Limbs bv = b.magToLimbs();
490 if (a.negative_ == b.negative_) {
491 r.setFromLimbs(addMag(av, bv), a.negative_);
493 const int c = cmpMag(av, bv);
495 r.setFromLimbs(subMag(av, bv), a.negative_);
497 r.setFromLimbs(subMag(bv, av), b.negative_);
508 const std::uint64_t u64max = pgl::detail::numeric_limits<std::uint64_t>::max();
509 if (a <= u64max && b <= u64max) {
510 return pgl::int128(
static_cast<std::uint64_t
>(a) /
static_cast<std::uint64_t
>(b));
517 const std::uint64_t u64max = pgl::detail::numeric_limits<std::uint64_t>::max();
518 if (a <= u64max && b <= u64max) {
519 return pgl::int128(
static_cast<std::uint64_t
>(a) %
static_cast<std::uint64_t
>(b));
531 throw std::domain_error(
"pgl::BigInt: division by zero");
533 const bool quotientNegative = a.negative_ != b.negative_;
534 const bool remainderNegative = a.negative_;
535 if (a.limbs_.empty() && b.limbs_.empty()) {
536 q = fromSmall(quotSmall(a.small_, b.small_), quotientNegative);
537 r = fromSmall(remSmall(a.small_, b.small_), remainderNegative);
540 auto [qm, rm] = divmodMag(a.magToLimbs(), b.magToLimbs());
541 q.setFromLimbs(std::move(qm), quotientNegative);
542 r.setFromLimbs(std::move(rm), remainderNegative);
553#if defined(__SIZEOF_INT128__)
555 for (std::size_t i = 0; i < limbs_.size() && i < 3; ++i) {
556 m +=
static_cast<__uint128_t
>(limbs_[i]) << (kLimbBits * i);
558 return static_cast<pgl::int128>(negative_ ? -m : m);
562 for (std::size_t i = 0; i < limbs_.size() && i < 3; ++i) {
563 m += limbs_[i] * weight;
566 return negative_ ? -m : m;
575 BigInt(pgl::detail::extended_integral
auto value) {
580 if (
x == pgl::detail::numeric_limits<pgl::int128>::min()) {
587 small_ =
x < 0 ? -
x :
x;
598 template <std::
floating_po
int Float>
600 assert(std::isfinite(value)
601 &&
"pgl::BigInt: cannot construct from non-finite floating point");
602 const bool neg = value < 0;
603 const Float mag = std::trunc(neg ? -value : value);
611 const Float frac = std::frexp(mag, &exponent);
612 const int digits = pgl::detail::numeric_limits<Float>::digits;
614 const int shift = exponent - digits;
617 small_ = sig >> (-shift);
624 Limbs v(
static_cast<std::size_t
>(shift / kLimbBits),
pgl::int128(0));
627 v.push_back(
x & limbMask());
630 setFromLimbs(std::move(v), neg);
636 bool isZero()
const {
return limbs_.empty() && small_ == 0; }
643 bool isOne()
const {
return limbs_.empty() && !negative_ && small_ == 1; }
657 return limbs_.empty() && small_ < (
pgl::int128(1) << 63);
665 bool fitsLimbs(std::size_t limbs)
const {
return limbs_.size() <= limbs; }
670 return negative_ ? -1 : 1;
684 if (limbs_.empty()) {
685 return negative_ ? -small_ : small_;
687 return lowBitsInt128();
698 template <std::
signed_
integral T>
699 explicit operator T()
const {
700 return static_cast<T
>(
static_cast<pgl::int128>(*this));
703 explicit operator bool()
const {
return !
isZero(); }
706 explicit operator long double()
const {
708 if (limbs_.empty()) {
709 d =
static_cast<long double>(small_);
711 const long double b =
static_cast<long double>(base());
712 for (std::size_t i = limbs_.size(); i-- > 0;) {
713 d = d * b +
static_cast<long double>(limbs_[i]);
716 return negative_ ? -d : d;
718 explicit operator double()
const {
return static_cast<double>(
static_cast<long double>(*this)); }
719 explicit operator float()
const {
return static_cast<float>(
static_cast<long double>(*this)); }
726 r.negative_ = !r.negative_;
734 if (a.limbs_.empty() && b.limbs_.empty()) {
737 if (a.negative_ == b.negative_) {
738 if (ma <= int128Max() - mb) {
739 return fromSmall(ma + mb, a.negative_);
742 }
else if (ma >= mb) {
743 return fromSmall(ma - mb, a.negative_);
745 return fromSmall(mb - ma, b.negative_);
748 return addGeneral(a, b);
752 if (a.limbs_.empty() && b.limbs_.empty()) {
757 if (a.negative_ != b.negative_) {
758 if (ma <= int128Max() - mb) {
759 return fromSmall(ma + mb, a.negative_);
761 }
else if (ma >= mb) {
762 return fromSmall(ma - mb, a.negative_);
764 return fromSmall(mb - ma, !a.negative_);
775 const bool neg = a.negative_ != b.negative_;
776 if (a.limbs_.empty() && b.limbs_.empty()) {
779#if defined(__SIZEOF_INT128__)
784 if (!__builtin_mul_overflow(ma, mb, &prod)) {
785 return fromSmall(prod, neg);
790 if (ma == 0 || mb <= int128Max() / ma) {
791 return fromSmall(ma * mb, neg);
803 out.setFromLimbs(mulMag(a.magToLimbs(), b.magToLimbs()), neg);
808 if (a.limbs_.empty() && b.limbs_.empty()) {
810 throw std::domain_error(
"pgl::BigInt: division by zero");
813 return fromSmall(quotSmall(a.small_, b.small_), a.negative_ != b.negative_);
822 if (a.limbs_.empty() && b.limbs_.empty()) {
824 throw std::domain_error(
"pgl::BigInt: division by zero");
827 return fromSmall(remSmall(a.small_, b.small_), a.negative_);
849 if (negative_ != o.negative_) {
850 return negative_ ? std::strong_ordering::less : std::strong_ordering::greater;
852 int c = compareMag(o);
856 if (c < 0)
return std::strong_ordering::less;
857 if (c > 0)
return std::strong_ordering::greater;
858 return std::strong_ordering::equal;
862 return negative_ == o.negative_ && compareMag(o) == 0;
875 template <std::
floating_po
int Float>
877 if (!std::isfinite(f) || f != std::trunc(f)) {
880 return *
this ==
BigInt(f);
884 template <std::
floating_po
int Float>
887 return std::partial_ordering::unordered;
890 return f > 0 ? std::partial_ordering::less : std::partial_ordering::greater;
894 const Float t = std::trunc(f);
895 if (std::strong_ordering c = *this <=>
BigInt(f); c != 0) {
901 return std::partial_ordering::equivalent;
903 return f > t ? std::partial_ordering::less : std::partial_ordering::greater;
912 if (b.limbs_.empty()) {
915 os << b.magToDecimalString();
921 std::istream::sentry sentry(is);
927 if (c ==
'+' || c ==
'-') {
932 if (c <
'0' || c >
'9') {
933 is.setstate(std::ios::failbit);
938 for (; c >=
'0' && c <=
'9'; c = is.peek()) {
940 result = result * ten +
BigInt(c -
'0');
942 b = neg ? -result : result;
952#undef PGL_BIGINT_COLD
#define PGL_BIGINT_COLD
Definition bigint.hpp:41
Arbitrary precision signed integer.
Definition bigint.hpp:157
bool fitsLimbs(std::size_t limbs) const
Whether the magnitude occupies at most limbs heap limbs.
Definition bigint.hpp:665
BigInt & operator*=(const BigInt &o)
Definition bigint.hpp:837
bool isNegative() const
Whether the value is strictly negative.
Definition bigint.hpp:646
static BigInt subGeneral(const BigInt &a, const BigInt &b)
Cold out-of-line subtraction fallback (a magnitude spilled to limbs).
Definition bigint.hpp:772
friend BigInt operator%(const BigInt &a, const BigInt &b)
Definition bigint.hpp:821
BigInt & operator--()
Definition bigint.hpp:843
friend BigInt operator/(const BigInt &a, const BigInt &b)
Definition bigint.hpp:807
friend std::ostream & operator<<(std::ostream &os, const BigInt &b)
Definition bigint.hpp:908
int sign() const
Sign of the value: -1, 0, or 1.
Definition bigint.hpp:668
BigInt & operator%=(const BigInt &o)
Definition bigint.hpp:839
BigInt operator--(int)
Definition bigint.hpp:844
bool operator==(const BigInt &o) const
Definition bigint.hpp:861
BigInt operator++(int)
Definition bigint.hpp:842
BigInt operator+() const
Definition bigint.hpp:731
friend std::istream & operator>>(std::istream &is, BigInt &b)
Definition bigint.hpp:920
BigInt operator-() const
Definition bigint.hpp:723
bool isOne() const
Whether the value is one.
Definition bigint.hpp:643
std::partial_ordering operator<=>(Float f) const
Ordering against a floating-point value (partial: NaN is unordered).
Definition bigint.hpp:885
BigInt()=default
Default constructor (zero).
friend BigInt operator-(const BigInt &a, const BigInt &b)
Definition bigint.hpp:751
friend BigInt operator+(const BigInt &a, const BigInt &b)
Definition bigint.hpp:733
BigInt(Float value)
Construct from floating point, truncating toward zero.
Definition bigint.hpp:599
BigInt & operator++()
Definition bigint.hpp:841
BigInt & operator-=(const BigInt &o)
Definition bigint.hpp:836
BigInt & operator/=(const BigInt &o)
Definition bigint.hpp:838
BigInt abs() const
Absolute value.
Definition bigint.hpp:674
BigInt(pgl::detail::extended_integral auto value)
Construct from any integer (including pgl::int128).
Definition bigint.hpp:575
std::strong_ordering operator<=>(const BigInt &o) const
Definition bigint.hpp:848
static BigInt mulGeneral(const BigInt &a, const BigInt &b, bool neg)
Cold out-of-line schoolbook multiplication (a magnitude exceeds int128).
Definition bigint.hpp:801
bool fitsInt128() const
Whether the magnitude fits in a single pgl::int128.
Definition bigint.hpp:649
bool fitsInt64() const
Whether the magnitude fits in 63 bits (i.e. in an int64_t).
Definition bigint.hpp:656
bool isZero() const
Whether the value is zero.
Definition bigint.hpp:636
friend BigInt operator*(const BigInt &a, const BigInt &b)
Definition bigint.hpp:774
bool operator==(Float f) const
Equality with a floating-point value (true only when f is a whole number equal to this integer).
Definition bigint.hpp:876
BigInt & operator+=(const BigInt &o)
Definition bigint.hpp:835
Definition arrangement.hpp:67
@ x
Definition intervaltree.hpp:24
BigInt abs(const BigInt &v)
Free-function absolute value, matching the integer helpers.
Definition bigint.hpp:948
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
Numeric concepts and helpers shared by exact geometry operations.