41 #include <initializer_list> 47 #include <type_traits> 52 #if __GNU_MP_VERSION < 5 54 #error Minimum supported GMP version is 5. 58 #if defined(MPPP_WITH_LONG_DOUBLE) 62 #if MPFR_VERSION_MAJOR < 3 64 #error Minimum supported MPFR version is 3. 71 #if defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER) 73 #define mppp_likely(x) __builtin_expect(!!(x), 1) 74 #define mppp_unlikely(x) __builtin_expect(!!(x), 0) 75 #define MPPP_RESTRICT __restrict 79 #if defined(__SIZEOF_INT128__) 80 #define MPPP_UINT128 __uint128_t 83 #elif defined(_MSC_VER) 91 #define mppp_likely(x) (x) 92 #define mppp_unlikely(x) (x) 93 #define MPPP_RESTRICT __restrict 97 #pragma warning(disable : 4127) 98 #pragma warning(disable : 4146) 99 #pragma warning(disable : 4804) 106 #define mppp_likely(x) (x) 107 #define mppp_unlikely(x) (x) 108 #define MPPP_RESTRICT 113 #if defined(__apple_build_version__) || defined(__MINGW32__) || defined(__INTEL_COMPILER) 118 #define MPPP_MAYBE_TLS 123 #define MPPP_HAVE_THREAD_LOCAL 124 #define MPPP_MAYBE_TLS static thread_local 129 #if defined(MPPP_CUSTOM_NAMESPACE) 131 #define MPPP_NAMESPACE MPPP_CUSTOM_NAMESPACE 135 #define MPPP_NAMESPACE mppp 140 namespace MPPP_NAMESPACE
149 template <
typename... Ts>
154 template <
typename... Ts>
155 using void_t =
typename make_void<Ts...>::type;
158 template <
class Default,
class AlwaysVoid,
template <
class...>
class Op,
class... Args>
160 using value_t = std::false_type;
161 using type = Default;
164 template <
class Default,
template <
class...>
class Op,
class... Args>
165 struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
166 using value_t = std::true_type;
167 using type = Op<Args...>;
173 ~nonesuch() =
delete;
174 nonesuch(nonesuch
const &) =
delete;
175 void operator=(nonesuch
const &) =
delete;
178 template <
template <
class...>
class Op,
class... Args>
179 using is_detected =
typename detector<nonesuch, void, Op, Args...>::value_t;
181 template <
template <
class...>
class Op,
class... Args>
182 using detected_t =
typename detector<nonesuch, void, Op, Args...>::type;
186 struct conjunction : std::true_type {
190 struct conjunction<B1> : B1 {
193 template <
class B1,
class... Bn>
194 struct conjunction<B1, Bn...> : std::conditional<B1::value != false, conjunction<Bn...>, B1>::type {
199 struct disjunction : std::false_type {
203 struct disjunction<B1> : B1 {
206 template <
class B1,
class... Bn>
207 struct disjunction<B1, Bn...> : std::conditional<B1::value != false, B1, disjunction<Bn...>>::type {
212 struct negation : std::integral_constant<bool, !B::value> {
216 using mpz_struct_t = std::remove_extent<::mpz_t>::type;
218 using mpz_alloc_t = decltype(std::declval<mpz_struct_t>()._mp_alloc);
219 using mpz_size_t = decltype(std::declval<mpz_struct_t>()._mp_size);
223 struct expected_mpz_struct_t {
224 mpz_alloc_t _mp_alloc;
229 static_assert(
sizeof(expected_mpz_struct_t) ==
sizeof(mpz_struct_t) && std::is_standard_layout<mpz_struct_t>::value
230 && std::is_standard_layout<expected_mpz_struct_t>::value && offsetof(mpz_struct_t, _mp_alloc) == 0u
231 && offsetof(mpz_struct_t, _mp_size) == offsetof(expected_mpz_struct_t, _mp_size)
232 && offsetof(mpz_struct_t, _mp_d) == offsetof(expected_mpz_struct_t, _mp_d)
233 && std::is_same<::mp_limb_t *, decltype(std::declval<mpz_struct_t>()._mp_d)>::value &&
236 std::is_unsigned<::mp_bitcnt_t>::value &&
240 std::numeric_limits<mpz_size_t>::min() >= std::numeric_limits<::mp_size_t>::min()
241 && std::numeric_limits<mpz_size_t>::max() <= std::numeric_limits<::mp_size_t>::max(),
242 "Invalid mpz_t struct layout and/or GMP types.");
245 inline void mpz_init_nlimbs(mpz_struct_t &rop, std::size_t nlimbs)
248 if (mppp_unlikely(nlimbs > std::numeric_limits<std::size_t>::max() /
unsigned(GMP_NUMB_BITS))) {
253 const auto nbits =
static_cast<std::size_t
>(unsigned(GMP_NUMB_BITS) * nlimbs);
254 if (mppp_unlikely(nbits > std::numeric_limits<::mp_bitcnt_t>::max())) {
258 ::mpz_init2(&rop, static_cast<::mp_bitcnt_t>(nbits));
259 assert(std::make_unsigned<mpz_size_t>::type(rop._mp_alloc) >= nlimbs);
263 inline void mpz_init_set_nlimbs(mpz_struct_t &m0,
const mpz_struct_t &m1)
265 mpz_init_nlimbs(m0, ::mpz_size(&m1));
274 assert(m_mpz._mp_alloc >= 0);
276 mpz_raii(
const mpz_raii &) =
delete;
277 mpz_raii(mpz_raii &&) =
delete;
278 mpz_raii &operator=(
const mpz_raii &) =
delete;
279 mpz_raii &operator=(mpz_raii &&) =
delete;
285 assert(m_mpz._mp_d !=
nullptr);
291 #if defined(MPPP_WITH_LONG_DOUBLE) 294 using mpfr_struct_t = std::remove_extent<::mpfr_t>::type;
300 ::mpfr_init2(&m_mpfr, 53);
304 ::mpfr_clear(&m_mpfr);
306 mpfr_struct_t m_mpfr;
310 static_assert(std::numeric_limits<long double>::digits10 < std::numeric_limits<int>::max() / 4,
"Overflow error.");
311 static_assert(std::numeric_limits<long double>::digits10 * 4 < std::numeric_limits<::mpfr_prec_t>::max(),
317 inline void mpz_to_str(std::vector<char> &out,
const mpz_struct_t *mpz,
int base = 10)
319 assert(base >= 2 && base <= 62);
320 const auto size_base = ::mpz_sizeinbase(mpz, base);
321 if (mppp_unlikely(size_base > std::numeric_limits<std::size_t>::max() - 2u)) {
322 throw std::overflow_error(
"Too many digits in the conversion of mpz_t to string.");
325 const auto total_size = size_base + 2u;
328 out.resize(
static_cast<std::vector<char>::size_type
>(total_size));
330 if (mppp_unlikely(out.size() != total_size)) {
331 throw std::overflow_error(
"Too many digits in the conversion of mpz_t to string.");
333 ::mpz_get_str(out.data(), base, mpz);
337 inline std::string mpz_to_str(
const mpz_struct_t *mpz,
int base = 10)
339 MPPP_MAYBE_TLS std::vector<char> tmp;
340 mpz_to_str(tmp, mpz, base);
345 template <
typename T>
346 using is_supported_integral
347 = std::integral_constant<bool, disjunction<std::is_same<T, bool>, std::is_same<T, char>,
348 std::is_same<T, signed char>, std::is_same<T, unsigned char>,
349 std::is_same<T, short>, std::is_same<T, unsigned short>,
350 std::is_same<T, int>, std::is_same<T, unsigned>, std::is_same<T, long>,
351 std::is_same<T, unsigned long>, std::is_same<T, long long>,
352 std::is_same<T, unsigned long long>>::value>;
355 template <
typename T>
356 using is_supported_float = std::integral_constant<bool, disjunction<std::is_same<T, float>, std::is_same<T, double>
357 #if defined(MPPP_WITH_LONG_DOUBLE) 359 std::is_same<T, long double>
363 template <
typename T>
364 using is_supported_interop
365 = std::integral_constant<bool, disjunction<is_supported_integral<T>, is_supported_float<T>>::value>;
368 inline void copy_limbs(const ::mp_limb_t *begin, const ::mp_limb_t *end, ::mp_limb_t *out)
370 for (; begin != end; ++begin, ++out) {
376 inline void copy_limbs_no(const ::mp_limb_t *begin, const ::mp_limb_t *end, ::mp_limb_t *MPPP_RESTRICT out)
378 assert(begin != out);
379 for (; begin != end; ++begin, ++out) {
387 inline ::mp_limb_t limb_add_overflow(::mp_limb_t a, ::mp_limb_t b, ::mp_limb_t *res)
394 template <std::
size_t SSize>
397 template <
bool B,
typename T =
void>
398 using enable_if_t =
typename std::enable_if<B, T>::type;
400 static_assert(SSize > 0u && SSize <= 64u,
"Invalid static size.");
401 using limbs_type = std::array<::mp_limb_t, SSize>;
403 static const mpz_size_t s_size = SSize;
405 static const mpz_alloc_t s_alloc = -1;
411 static const std::size_t opt_size = 2;
415 static_int() : _mp_alloc(s_alloc), _mp_size(0), m_limbs()
419 static_int(
const static_int &) =
default;
420 static_int(static_int &&) =
default;
421 static_int &operator=(
const static_int &) =
default;
422 static_int &operator=(static_int &&) =
default;
423 bool dtor_checks()
const 425 const auto asize = abs_size();
427 if (_mp_alloc != s_alloc) {
431 if (asize > s_size) {
436 if (SSize <= opt_size) {
437 for (
auto i = static_cast<std::size_t>(asize); i < SSize; ++i) {
444 if (asize > 0 && (m_limbs[static_cast<std::size_t>(asize - 1)] & GMP_NUMB_MASK) == 0u) {
451 assert(dtor_checks());
457 void zero_unused_limbs()
461 if (SSize <= opt_size) {
462 for (
auto i = static_cast<std::size_t>(abs_size()); i < SSize; ++i) {
468 mpz_size_t abs_size()
const 470 return _mp_size >= 0 ? _mp_size : -_mp_size;
472 struct static_mpz_view {
480 static_mpz_view() : m_mpz()
488 explicit static_mpz_view(
const static_int &n)
489 : m_mpz{s_size, n._mp_size,
const_cast<::mp_limb_t *
>(n.m_limbs.data())}
492 static_mpz_view(static_mpz_view &&) =
default;
493 static_mpz_view(
const static_mpz_view &) =
delete;
494 static_mpz_view &operator=(
const static_mpz_view &) =
delete;
495 static_mpz_view &operator=(static_mpz_view &&) =
delete;
496 operator const mpz_struct_t *()
const 502 static_mpz_view get_mpz_view()
const 504 return static_mpz_view{*
this};
506 mpz_alloc_t _mp_alloc;
512 template <std::
size_t SSize>
513 union integer_union {
515 using s_storage = static_int<SSize>;
516 using d_storage = mpz_struct_t;
518 integer_union() : m_st()
522 integer_union(
const integer_union &other)
524 if (other.is_static()) {
525 ::new (static_cast<void *>(&m_st)) s_storage(other.g_st());
527 ::new (static_cast<void *>(&m_dy)) d_storage;
528 mpz_init_set_nlimbs(m_dy, other.g_dy());
529 assert(m_dy._mp_alloc >= 0);
533 integer_union(integer_union &&other) noexcept
535 if (other.is_static()) {
536 ::new (static_cast<void *>(&m_st)) s_storage(std::move(other.g_st()));
538 ::new (static_cast<void *>(&m_dy)) d_storage;
542 other.g_dy().~d_storage();
543 ::new (static_cast<void *>(&other.m_st)) s_storage();
547 integer_union &operator=(
const integer_union &other)
549 if (mppp_unlikely(
this == &other)) {
552 const bool s1 = is_static(), s2 = other.is_static();
554 g_st() = other.g_st();
555 }
else if (s1 && !s2) {
559 ::new (static_cast<void *>(&m_dy)) d_storage;
561 mpz_init_set_nlimbs(m_dy, other.g_dy());
562 assert(m_dy._mp_alloc >= 0);
563 }
else if (!s1 && s2) {
567 ::new (static_cast<void *>(&m_st)) s_storage(other.g_st());
569 ::mpz_set(&g_dy(), &other.g_dy());
575 integer_union &operator=(integer_union &&other) noexcept
577 if (mppp_unlikely(
this == &other)) {
580 const bool s1 = is_static(), s2 = other.is_static();
582 g_st() = std::move(other.g_st());
583 }
else if (s1 && !s2) {
587 ::new (static_cast<void *>(&m_dy)) d_storage;
590 other.g_dy().~d_storage();
591 ::new (static_cast<void *>(&other.m_st)) s_storage();
592 }
else if (!s1 && s2) {
595 ::new (static_cast<void *>(&m_st)) s_storage(other.g_st());
598 ::mpz_swap(&g_dy(), &other.g_dy());
610 void destroy_dynamic()
612 assert(!is_static());
613 assert(g_dy()._mp_alloc >= 0);
614 assert(g_dy()._mp_d !=
nullptr);
615 ::mpz_clear(&g_dy());
619 bool is_static()
const 621 return m_st._mp_alloc == s_storage::s_alloc;
623 bool is_dynamic()
const 625 return m_st._mp_alloc != s_storage::s_alloc;
628 const s_storage &g_st()
const 638 const d_storage &g_dy()
const 640 assert(is_dynamic());
645 assert(is_dynamic());
650 void promote(std::size_t nlimbs = 0u)
653 mpz_struct_t tmp_mpz;
654 auto v = g_st().get_mpz_view();
658 mpz_init_set_nlimbs(tmp_mpz, *v);
662 mpz_init_nlimbs(tmp_mpz, nlimbs);
663 ::mpz_set(&tmp_mpz, v);
668 ::new (static_cast<void *>(&m_dy)) d_storage;
674 assert(is_dynamic());
675 const auto dyn_size = ::mpz_size(&g_dy());
677 if (dyn_size > SSize) {
681 std::array<::mp_limb_t, SSize> tmp;
682 copy_limbs_no(g_dy()._mp_d, g_dy()._mp_d + dyn_size, tmp.data());
683 const auto signed_size = g_dy()._mp_size;
689 ::new (static_cast<void *>(&m_st)) s_storage();
690 g_st()._mp_size = signed_size;
691 copy_limbs_no(tmp.data(), tmp.data() + dyn_size, g_st().m_limbs.data());
706 using std::domain_error::domain_error;
868 template <std::
size_t SSize>
872 template <
bool B,
typename T =
void>
873 using enable_if_t =
typename std::enable_if<B, T>::type;
875 using s_storage = mppp_impl::static_int<SSize>;
876 using d_storage = mppp_impl::mpz_struct_t;
877 using mpz_size_t = mppp_impl::mpz_size_t;
878 using mpz_raii = mppp_impl::mpz_raii;
879 using mpz_struct_t = mppp_impl::mpz_struct_t;
880 #if defined(MPPP_WITH_LONG_DOUBLE) 881 using mpfr_raii = mppp_impl::mpfr_raii;
883 template <
typename T>
884 using is_supported_integral = mppp_impl::is_supported_integral<T>;
885 template <
typename T>
886 using is_supported_float = mppp_impl::is_supported_float<T>;
887 template <
typename T>
888 using is_supported_interop = mppp_impl::is_supported_interop<T>;
889 template <
template <
class...>
class Op,
class... Args>
890 using is_detected = mppp_impl::is_detected<Op, Args...>;
891 template <
typename... Args>
892 using conjunction = mppp_impl::conjunction<Args...>;
893 template <
typename... Args>
894 using disjunction = mppp_impl::disjunction<Args...>;
895 template <
typename T>
896 using negation = mppp_impl::negation<T>;
898 using s_int = s_storage;
901 using static_mpz_view =
typename s_int::static_mpz_view;
903 : m_static_view(n.
is_static() ? n.m_int.g_st().get_mpz_view() : static_mpz_view{}),
904 m_ptr(n.
is_static() ? m_static_view : &(n.m_int.g_dy()))
907 mpz_view(
const mpz_view &) =
delete;
908 mpz_view(mpz_view &&other)
909 : m_static_view(std::move(other.m_static_view)),
913 m_ptr((other.m_ptr == other.m_static_view) ? m_static_view : other.m_ptr)
916 mpz_view &operator=(
const mpz_view &) =
delete;
917 mpz_view &operator=(mpz_view &&) =
delete;
918 operator const mpz_struct_t *()
const 922 const mpz_struct_t *
get()
const 926 static_mpz_view m_static_view;
927 const mpz_struct_t *m_ptr;
935 template <
typename,
typename,
typename =
void>
938 template <
typename T>
939 struct common_type<T, T, enable_if_t<
std::is_same<T, mp_integer>::value>> {
942 template <
typename T,
typename U>
943 struct common_type<T, U, enable_if_t<conjunction<
std::is_same<T, mp_integer>, is_supported_integral<U>>::value>> {
946 template <
typename T,
typename U>
947 struct common_type<T, U, enable_if_t<conjunction<
std::is_same<U, mp_integer>, is_supported_integral<T>>::value>> {
950 template <
typename T,
typename U>
951 struct common_type<T, U, enable_if_t<conjunction<
std::is_same<T, mp_integer>, is_supported_float<U>>::value>> {
954 template <
typename T,
typename U>
955 struct common_type<T, U, enable_if_t<conjunction<
std::is_same<U, mp_integer>, is_supported_float<T>>::value>> {
958 template <
typename T,
typename U>
959 using common_t =
typename common_type<T, U>::type;
961 template <
typename T>
962 using in_place_enabler = enable_if_t<disjunction<is_supported_interop<T>, std::is_same<T, mp_integer>>::value,
int>;
963 #if defined(_MSC_VER) 968 template <
typename T>
969 using shift_op_enabler = enable_if_t<is_supported_integral<T>::value,
mp_integer>;
971 template <
typename T>
972 using shift_op_enabler = enable_if_t<is_supported_integral<T>::value,
int>;
974 template <typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
975 static ::mp_bitcnt_t cast_to_bitcnt(T n)
977 if (mppp_unlikely(n > std::numeric_limits<::mp_bitcnt_t>::max())) {
978 throw std::domain_error(
"Cannot bit shift by " + std::to_string(n) +
": the value is too large");
980 return static_cast<::mp_bitcnt_t
>(n);
982 template <typename T, enable_if_t<std::is_signed<T>::value,
int> = 0>
983 static ::mp_bitcnt_t cast_to_bitcnt(T n)
985 if (mppp_unlikely(n < T(0))) {
986 throw std::domain_error(
"Cannot bit shift by " + std::to_string(n) +
": negative values are not supported");
988 if (mppp_unlikely(
static_cast<typename std::make_unsigned<T>::type
>(n)
989 > std::numeric_limits<::mp_bitcnt_t>::max())) {
990 throw std::domain_error(
"Cannot bit shift by " + std::to_string(n) +
": the value is too large");
992 return static_cast<::mp_bitcnt_t
>(n);
997 static constexpr std::size_t ssize = SSize;
1021 template <
typename T>
1022 using generic_ctor_enabler = enable_if_t<is_supported_interop<T>::value,
int>;
1024 template <
typename T>
1025 using generic_assignment_enabler = generic_ctor_enabler<T>;
1029 void push_limb(::mp_limb_t l)
1031 const auto asize = m_int.m_st._mp_size;
1034 if (std::size_t(asize) < SSize) {
1037 ++m_int.g_st()._mp_size;
1038 m_int.g_st().m_limbs[std::size_t(asize)] = l;
1042 const auto limb_copy = m_int.g_st().m_limbs[SSize - 1u];
1048 m_int.g_st().m_limbs[SSize - 1u] = 1u;
1050 m_int.promote(SSize + 1u);
1052 m_int.g_dy()._mp_d[SSize - 1u] = limb_copy;
1054 if (m_int.g_dy()._mp_alloc == asize) {
1060 const auto limb_copy = m_int.g_dy()._mp_d[asize - 1];
1061 m_int.g_dy()._mp_d[asize - 1] = 1u;
1062 ::mpz_realloc2(&m_int.g_dy(),
static_cast<::mp_bitcnt_t
>(asize) * 2u * GMP_NUMB_BITS);
1063 if (mppp_unlikely(m_int.g_dy()._mp_alloc / 2 != asize)) {
1067 m_int.g_dy()._mp_d[asize - 1] = limb_copy;
1070 ++m_int.g_dy()._mp_size;
1071 m_int.g_dy()._mp_d[asize] = l;
1076 template <typename T, enable_if_t<(GMP_NUMB_BITS < unsigned(std::numeric_limits<T>::digits)),
int> = 0>
1077 static void checked_rshift(T &n)
1079 n >>= GMP_NUMB_BITS;
1081 template <
typename T, enable_if_t<(GMP_NUMB_BITS >=
unsigned(std::numeric_limits<T>::digits)),
int> = 0>
1082 static void checked_rshift(T &)
1087 template <
typename T, enable_if_t<conjunction<std::is_
integral<T>, std::is_
unsigned<T>>::value,
int> = 0>
1088 void dispatch_generic_ctor(T n)
1090 auto nu =
static_cast<unsigned long long>(n);
1092 push_limb(static_cast<::mp_limb_t>(nu & GMP_NUMB_MASK));
1093 if (GMP_NUMB_BITS >=
unsigned(std::numeric_limits<unsigned long long>::digits)) {
1099 template <
typename T, enable_if_t<conjunction<std::is_
integral<T>, std::is_
signed<T>>::value,
int> = 0>
1100 void dispatch_generic_ctor(T n)
1114 const auto nu =
static_cast<unsigned long long>(n);
1116 dispatch_generic_ctor(nu);
1118 dispatch_generic_ctor(-nu);
1122 template <
typename T, enable_if_t<disjunction<std::is_same<T,
float>, std::is_same<T,
double>>::value,
int> = 0>
1123 void dispatch_generic_ctor(T x)
1125 if (mppp_unlikely(!std::isfinite(x))) {
1126 throw std::domain_error(
"Cannot init integer from the non-finite floating-point value " 1127 + std::to_string(x));
1129 MPPP_MAYBE_TLS mpz_raii tmp;
1130 ::mpz_set_d(&tmp.m_mpz, static_cast<double>(x));
1131 dispatch_mpz_ctor(&tmp.m_mpz);
1133 #if defined(MPPP_WITH_LONG_DOUBLE) 1134 template <typename T, enable_if_t<std::is_same<T, long double>::value,
int> = 0>
1135 void dispatch_generic_ctor(T x)
1137 if (mppp_unlikely(!std::isfinite(x))) {
1138 throw std::domain_error(
"Cannot init integer from the non-finite floating-point value " 1139 + std::to_string(x));
1141 MPPP_MAYBE_TLS mpfr_raii mpfr;
1142 MPPP_MAYBE_TLS mpz_raii tmp;
1144 constexpr
int d2 = std::numeric_limits<long double>::digits10 * 4;
1145 ::mpfr_set_prec(&mpfr.m_mpfr, static_cast<::mpfr_prec_t>(d2));
1146 ::mpfr_set_ld(&mpfr.m_mpfr, x, MPFR_RNDN);
1147 ::mpfr_get_z(&tmp.m_mpz, &mpfr.m_mpfr, MPFR_RNDZ);
1148 dispatch_mpz_ctor(&tmp.m_mpz);
1152 void dispatch_mpz_ctor(const ::mpz_t n)
1154 const auto asize = ::mpz_size(n);
1155 if (asize > SSize) {
1158 m_int.g_st().~s_storage();
1160 ::new (static_cast<void *>(&m_int.m_dy)) d_storage;
1161 mppp_impl::mpz_init_set_nlimbs(m_int.m_dy, *n);
1166 m_int.g_st()._mp_size = n->_mp_size;
1167 mppp_impl::copy_limbs_no(n->_mp_d, n->_mp_d + asize, m_int.g_st().m_limbs.data());
1185 template <
typename T,
generic_ctor_enabler<T> = 0>
1188 dispatch_generic_ctor(x);
1207 if (mppp_unlikely(base != 0 && (base < 2 || base > 62))) {
1208 throw std::invalid_argument(
1209 "In the constructor from string, a base of " + std::to_string(base)
1210 +
" was specified, but the only valid values are 0 and any value in the [2,62] range");
1212 MPPP_MAYBE_TLS mpz_raii mpz;
1213 if (mppp_unlikely(::mpz_set_str(&mpz.m_mpz, s, base))) {
1215 throw std::invalid_argument(std::string(
"The string '") + s +
"' is not a valid integer in base " 1216 + std::to_string(base));
1218 throw std::invalid_argument(std::string(
"The string '") + s
1219 +
"' is not a valid integer any supported base");
1222 dispatch_mpz_ctor(&mpz.m_mpz);
1246 dispatch_mpz_ctor(n);
1283 template <
typename T,
generic_assignment_enabler<T> = 0>
1294 return m_int.is_static();
1302 return m_int.is_dynamic();
1333 MPPP_MAYBE_TLS std::string tmp_str;
1334 std::getline(is, tmp_str);
1352 if (mppp_unlikely(base < 2 || base > 62)) {
1353 throw std::invalid_argument(
"Invalid base for string conversion: the base must be between " 1354 "2 and 62, but a value of " 1355 + std::to_string(base) +
" was provided instead");
1357 return mppp_impl::mpz_to_str(get_mpz_view(), base);
1364 template <
typename T>
1365 using generic_conversion_enabler = generic_ctor_enabler<T>;
1367 template <typename T, enable_if_t<std::is_same<bool, T>::value,
int> = 0>
1368 std::pair<bool, T> dispatch_conversion()
const 1370 return {
true, m_int.m_st._mp_size != 0};
1374 std::pair<bool, unsigned long long> convert_to_ull()
const 1376 const auto asize = size();
1379 const ::mp_limb_t *ptr = is_static() ? m_int.g_st().m_limbs.data() : m_int.g_dy()._mp_d;
1381 auto retval =
static_cast<unsigned long long>(ptr[0] & GMP_NUMB_MASK);
1383 unsigned long long shift = GMP_NUMB_BITS;
1384 constexpr
unsigned ull_bits = std::numeric_limits<unsigned long long>::digits;
1385 for (std::size_t i = 1u; i < asize; ++i, shift += GMP_NUMB_BITS) {
1386 if (shift >= ull_bits) {
1390 return {
false, 0ull};
1392 const auto l =
static_cast<unsigned long long>(ptr[i] & GMP_NUMB_MASK);
1393 if (l >> (ull_bits - shift)) {
1397 return {
false, 0ull};
1400 retval += l << shift;
1402 return {
true, retval};
1405 template <
typename T,
1406 enable_if_t<conjunction<std::is_integral<T>, std::is_unsigned<T>, negation<std::is_same<bool, T>>>::value,
1408 std::pair<bool, T> dispatch_conversion()
const 1411 if (!m_int.m_st._mp_size) {
1412 return {
true, T(0)};
1415 if (m_int.m_st._mp_size < 0) {
1416 return {
false, T(0)};
1419 const auto candidate = convert_to_ull();
1420 if (!candidate.first) {
1422 return {
false, T(0)};
1424 if (candidate.second > std::numeric_limits<T>::max()) {
1426 return {
false, T(0)};
1429 return {
true,
static_cast<T
>(candidate.second)};
1432 template <
typename T, enable_if_t<conjunction<std::is_
integral<T>, std::is_
signed<T>>::value,
int> = 0>
1433 std::pair<bool, T> dispatch_conversion()
const 1439 using uT =
typename std::make_unsigned<T>::type;
1441 if (!m_int.m_st._mp_size) {
1442 return {
true, T(0)};
1445 const auto candidate = convert_to_ull();
1446 if (!candidate.first) {
1448 return {
false, T(0)};
1450 if (m_int.m_st._mp_size > 0) {
1453 if (candidate.second > uT(std::numeric_limits<T>::max())) {
1454 return {
false, T(0)};
1456 return {
true,
static_cast<T
>(candidate.second)};
1462 constexpr
auto min_abs = -
static_cast<unsigned long long>(std::numeric_limits<T>::min());
1463 constexpr
auto max =
static_cast<unsigned long long>(std::numeric_limits<T>::max());
1464 if (candidate.second > min_abs) {
1466 return {
false, T(0)};
1472 constexpr
auto ceil_ratio = min_abs / max + unsigned((min_abs % max) != 0u);
1473 const unsigned long long q = candidate.second / ceil_ratio, r = candidate.second % ceil_ratio;
1474 auto retval =
static_cast<T
>(-
static_cast<T
>(q));
1475 static_assert(ceil_ratio <= uT(std::numeric_limits<T>::max()),
"Overflow error.");
1476 retval =
static_cast<T
>(retval *
static_cast<T
>(ceil_ratio));
1477 retval =
static_cast<T
>(retval -
static_cast<T
>(r));
1478 return {
true, retval};
1482 template <
typename T, enable_if_t<disjunction<std::is_same<T,
float>, std::is_same<T,
double>>::value,
int> = 0>
1483 static std::pair<bool, T> mpz_float_conversion(
const mpz_struct_t &m)
1485 return {
true,
static_cast<T
>(::mpz_get_d(&m))};
1487 #if defined(MPPP_WITH_LONG_DOUBLE) 1488 template <typename T, enable_if_t<std::is_same<T, long double>::value,
int> = 0>
1489 static std::pair<bool, T> mpz_float_conversion(
const mpz_struct_t &m)
1491 MPPP_MAYBE_TLS mpfr_raii mpfr;
1492 constexpr
int d2 = std::numeric_limits<long double>::digits10 * 4;
1493 ::mpfr_set_prec(&mpfr.m_mpfr, static_cast<::mpfr_prec_t>(d2));
1494 ::mpfr_set_z(&mpfr.m_mpfr, &m, MPFR_RNDN);
1495 return {
true, ::mpfr_get_ld(&mpfr.m_mpfr, MPFR_RNDN)};
1499 template <typename T, enable_if_t<std::is_floating_point<T>::value,
int> = 0>
1500 std::pair<bool, T> dispatch_conversion()
const 1503 if (!m_int.m_st._mp_size) {
1504 return {
true, T(0)};
1506 if (std::numeric_limits<T>::is_iec559) {
1524 const ::mp_limb_t *ptr = is_static() ? m_int.g_st().m_limbs.data() : m_int.g_dy()._mp_d;
1525 if (m_int.m_st._mp_size == 1) {
1526 return {
true,
static_cast<T
>(ptr[0] & GMP_NUMB_MASK)};
1528 if (m_int.m_st._mp_size == -1) {
1529 return {
true, -
static_cast<T
>(ptr[0] & GMP_NUMB_MASK)};
1533 return mpz_float_conversion<T>(*
static_cast<const mpz_struct_t *
>(get_mpz_view()));
1549 template <
typename T,
generic_conversion_enabler<T> = 0>
1550 explicit operator T()
const 1552 const auto retval = dispatch_conversion<T>();
1553 if (mppp_unlikely(!retval.first)) {
1554 throw std::overflow_error(
"Conversion of the integer " + to_string() +
" to the type " +
typeid(T).name()
1555 +
" results in overflow");
1557 return retval.second;
1584 return m_int.demote();
1594 return m_int.m_st._mp_size ? ::mpz_sizeinbase(get_mpz_view(), 2) : 0u;
1603 return std::size_t(m_int.g_st().abs_size());
1605 return ::mpz_size(&m_int.g_dy());
1614 if (m_int.m_st._mp_size != 0) {
1615 return m_int.m_st._mp_size > 0 ? 1 : -1;
1654 return mpz_view(*
this);
1665 m_int.g_st()._mp_size = -m_int.g_st()._mp_size;
1667 ::mpz_neg(&m_int.g_dy(), &m_int.g_dy());
1702 template <
typename SInt>
1703 using static_add_algo = std::integral_constant<int, (!GMP_NAIL_BITS && SInt::s_size == 1)
1705 : ((!GMP_NAIL_BITS && SInt::s_size == 2) ? 2 : 0)>;
1708 static mpz_size_t sub_compute_size(const ::mp_limb_t *rdata, mpz_size_t s)
1711 mpz_size_t cur_idx = s - 1;
1712 for (; cur_idx >= 0; --cur_idx) {
1713 if (rdata[cur_idx] & GMP_NUMB_MASK) {
1721 static bool static_add_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asize1, mpz_size_t asize2,
1722 int sign1,
int sign2,
const std::integral_constant<int, 0> &)
1724 using mppp_impl::copy_limbs;
1725 auto rdata = &rop.m_limbs[0];
1726 auto data1 = &op1.m_limbs[0], data2 = &op2.m_limbs[0];
1727 const auto size1 = op1._mp_size;
1730 const auto size2 = (sign2 >= 0) ? asize2 : -asize2;
1732 if (mppp_unlikely(!sign2)) {
1733 rop._mp_size = size1;
1734 copy_limbs(data1, data1 + asize1, rdata);
1737 if (mppp_unlikely(!sign1)) {
1738 rop._mp_size = size2;
1739 copy_limbs(data2, data2 + asize2, rdata);
1754 const bool c1 = std::size_t(asize1) == SSize && ((data1[asize1 - 1] & GMP_NUMB_MASK) >> (GMP_NUMB_BITS - 1));
1755 const bool c2 = std::size_t(asize2) == SSize && ((data2[asize2 - 1] & GMP_NUMB_MASK) >> (GMP_NUMB_BITS - 1));
1756 if (mppp_unlikely(c1 || c2)) {
1759 if (sign1 == sign2) {
1761 if (asize1 >= asize2) {
1767 cy = ::mpn_add_1(rdata, data1, static_cast<::mp_size_t>(asize1), data2[0]);
1768 }
else if (asize1 == asize2) {
1769 cy = ::mpn_add_n(rdata, data1, data2, static_cast<::mp_size_t>(asize1));
1771 cy = ::mpn_add(rdata, data1, static_cast<::mp_size_t>(asize1), data2,
1772 static_cast<::mp_size_t>(asize2));
1775 assert(asize1 < s_int::s_size);
1776 rop._mp_size = size1 + sign1;
1781 rop._mp_size = size1;
1787 cy = ::mpn_add_1(rdata, data2, static_cast<::mp_size_t>(asize2), data1[0]);
1789 cy = ::mpn_add(rdata, data2, static_cast<::mp_size_t>(asize2), data1,
1790 static_cast<::mp_size_t>(asize1));
1793 assert(asize2 < s_int::s_size);
1794 rop._mp_size = size2 + sign2;
1797 rop._mp_size = size2;
1802 || (asize1 == asize2 && ::mpn_cmp(data1, data2, static_cast<::mp_size_t>(asize1)) >= 0)) {
1806 br = ::mpn_sub_1(rdata, data1, static_cast<::mp_size_t>(asize1), data2[0]);
1807 }
else if (asize1 == asize2) {
1808 br = ::mpn_sub_n(rdata, data1, data2, static_cast<::mp_size_t>(asize1));
1810 br = ::mpn_sub(rdata, data1, static_cast<::mp_size_t>(asize1), data2,
1811 static_cast<::mp_size_t>(asize2));
1814 rop._mp_size = sub_compute_size(rdata, asize1);
1816 rop._mp_size = -rop._mp_size;
1822 br = ::mpn_sub_1(rdata, data2, static_cast<::mp_size_t>(asize2), data1[0]);
1824 br = ::mpn_sub(rdata, data2, static_cast<::mp_size_t>(asize2), data1,
1825 static_cast<::mp_size_t>(asize1));
1828 rop._mp_size = sub_compute_size(rdata, asize2);
1830 rop._mp_size = -rop._mp_size;
1837 static bool static_add_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asize1, mpz_size_t asize2,
1838 int sign1,
int sign2,
const std::integral_constant<int, 1> &)
1840 using mppp_impl::limb_add_overflow;
1841 auto rdata = &rop.m_limbs[0];
1842 auto data1 = &op1.m_limbs[0], data2 = &op2.m_limbs[0];
1844 assert((asize1 == 1 && data1[0] != 0u) || (asize1 == 0 && data1[0] == 0u));
1845 assert((asize2 == 1 && data2[0] != 0u) || (asize2 == 0 && data2[0] == 0u));
1847 if (sign1 == sign2) {
1849 if (mppp_unlikely(limb_add_overflow(data1[0], data2[0], &tmp))) {
1853 rop._mp_size = sign1;
1858 if (data1[0] >= data2[0]) {
1860 tmp = data1[0] - data2[0];
1862 rop._mp_size = sign1;
1863 if (mppp_unlikely(!tmp)) {
1869 rop._mp_size = sign2;
1870 rdata[0] = data2[0] - data1[0];
1877 static int compare_limbs_2(const ::mp_limb_t *data1, const ::mp_limb_t *data2, mpz_size_t asize)
1880 assert(!GMP_NAIL_BITS);
1881 assert(asize == 1 || asize == 2);
1883 auto cmp_idx = asize - 1;
1884 if (data1[cmp_idx] != data2[cmp_idx]) {
1885 return data1[cmp_idx] > data2[cmp_idx] ? 1 : -1;
1893 if (data1[cmp_idx] != data2[cmp_idx]) {
1894 return data1[cmp_idx] > data2[cmp_idx] ? 1 : -1;
1898 static bool static_add_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asize1, mpz_size_t asize2,
1899 int sign1,
int sign2,
const std::integral_constant<int, 2> &)
1901 using mppp_impl::limb_add_overflow;
1902 auto rdata = &rop.m_limbs[0];
1903 auto data1 = &op1.m_limbs[0], data2 = &op2.m_limbs[0];
1904 if (sign1 == sign2) {
1917 const auto a = data1[0], b = data2[0], c = data1[1], d = data2[1];
1918 ::mp_limb_t lo, hi1, hi2;
1919 const ::mp_limb_t cy_lo = limb_add_overflow(a, b, &lo), cy_hi1 = limb_add_overflow(c, d, &hi1),
1920 cy_hi2 = limb_add_overflow(hi1, cy_lo, &hi2);
1922 if (mppp_unlikely(cy_hi1 || cy_hi2)) {
1929 rop._mp_size = sign1;
1931 rop._mp_size = sign1 + sign1;
1938 if (asize1 > asize2 || (asize1 == asize2 && compare_limbs_2(data1, data2, asize1) >= 0)) {
1940 const auto lo = data1[0] - data2[0];
1942 assert(data1[0] >= data2[0] || data1[1] > data2[1]);
1944 const auto hi = data1[1] - data2[1] -
static_cast<::mp_limb_t
>(data1[0] < data2[0]);
1948 rop._mp_size = sign1 + sign1;
1950 rop._mp_size = sign1;
1956 const auto lo = data2[0] - data1[0];
1957 assert(data2[0] >= data1[0] || data2[1] > data1[1]);
1958 const auto hi = data2[1] - data1[1] -
static_cast<::mp_limb_t
>(data2[0] < data1[0]);
1960 rop._mp_size = sign2;
1962 rop._mp_size = sign2 + sign2;
1970 template <
bool AddOrSub>
1971 static bool static_addsub(s_int &rop,
const s_int &op1,
const s_int &op2)
1974 mpz_size_t asize1 = op1._mp_size, asize2 = AddOrSub ? op2._mp_size : -op2._mp_size;
1975 int sign1 = asize1 != 0, sign2 = asize2 != 0;
1984 const bool retval = static_add_impl(rop, op1, op2, asize1, asize2, sign1, sign2, static_add_algo<s_int>{});
1985 if (static_add_algo<s_int>::value == 0 && retval) {
1988 rop.zero_unused_limbs();
1993 static mp_integer dispatch_binary_add(
const mp_integer &op1,
const mp_integer &op2)
1996 add(retval, op1, op2);
1999 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2000 static mp_integer dispatch_binary_add(
const mp_integer &op1, T n)
2003 add(retval, retval, op1);
2006 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2007 static mp_integer dispatch_binary_add(T n,
const mp_integer &op2)
2009 return dispatch_binary_add(op2, n);
2011 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2012 static T dispatch_binary_add(
const mp_integer &op1, T x)
2014 return static_cast<T
>(op1) + x;
2016 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2017 static T dispatch_binary_add(T x,
const mp_integer &op2)
2019 return dispatch_binary_add(op2, x);
2022 static void dispatch_in_place_add(mp_integer &retval,
const mp_integer &n)
2024 add(retval, retval, n);
2026 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2027 static void dispatch_in_place_add(mp_integer &retval,
const T &n)
2029 add(retval, retval, mp_integer{n});
2031 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2032 static void dispatch_in_place_add(mp_integer &retval,
const T &x)
2034 retval =
static_cast<T
>(retval) + x;
2037 static mp_integer dispatch_binary_sub(
const mp_integer &op1,
const mp_integer &op2)
2040 sub(retval, op1, op2);
2043 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2044 static mp_integer dispatch_binary_sub(
const mp_integer &op1, T n)
2047 sub(retval, retval, op1);
2051 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2052 static mp_integer dispatch_binary_sub(T n,
const mp_integer &op2)
2054 auto retval = dispatch_binary_sub(op2, n);
2058 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2059 static T dispatch_binary_sub(
const mp_integer &op1, T x)
2061 return static_cast<T
>(op1) - x;
2063 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2064 static T dispatch_binary_sub(T x,
const mp_integer &op2)
2066 return -dispatch_binary_sub(op2, x);
2069 static void dispatch_in_place_sub(mp_integer &retval,
const mp_integer &n)
2071 sub(retval, retval, n);
2073 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2074 static void dispatch_in_place_sub(mp_integer &retval,
const T &n)
2076 sub(retval, retval, mp_integer{n});
2078 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2079 static void dispatch_in_place_sub(mp_integer &retval,
const T &x)
2081 retval =
static_cast<T
>(retval) - x;
2096 if (mppp_likely(sr && s1 && s2)) {
2098 if (mppp_likely(static_addsub<true>(rop.m_int.g_st(), op1.m_int.g_st(), op2.m_int.g_st()))) {
2103 rop.m_int.promote(SSize + 1u);
2122 template <
typename T,
typename U>
2125 return dispatch_binary_add(op1, op2);
2136 template <
typename T, in_place_enabler<T> = 0>
2139 dispatch_in_place_add(*
this, op);
2144 #if defined(_MSC_VER) 2145 template <
typename T>
2146 using in_place_lenabler = enable_if_t<is_supported_interop<T>::value, T &>;
2148 template <
typename T>
2149 using in_place_lenabler = enable_if_t<is_supported_interop<T>::value,
int>;
2153 #if defined(_MSC_VER) 2154 template <
typename T>
2155 friend in_place_lenabler<T> operator+=(T &x,
const mp_integer &n)
2175 template <
typename T, in_place_lenabler<T> = 0>
2182 return x =
static_cast<T
>(x + n);
2192 add_ui(*
this, *
this, 1u);
2218 if (mppp_likely(sr && s1 && s2)) {
2220 if (mppp_likely(static_addsub<false>(rop.m_int.g_st(), op1.m_int.g_st(), op2.m_int.g_st()))) {
2225 rop.m_int.promote(SSize + 1u);
2246 template <
typename T,
typename U>
2249 return dispatch_binary_sub(op1, op2);
2260 template <
typename T, in_place_enabler<T> = 0>
2263 dispatch_in_place_sub(*
this, op);
2266 #if defined(_MSC_VER) 2267 template <
typename T>
2268 friend in_place_lenabler<T> operator-=(T &x,
const mp_integer &n)
2288 template <
typename T, in_place_lenabler<T> = 0>
2292 return x =
static_cast<T
>(x - n);
2304 add_ui(*
this, *
this, 1u);
2327 template <
typename SInt>
2328 using static_add_ui_algo = std::integral_constant<int, (!GMP_NAIL_BITS && SInt::s_size == 1)
2330 : ((!GMP_NAIL_BITS && SInt::s_size == 2) ? 2 : 0)>;
2332 static bool static_add_ui_impl(s_int &rop,
const s_int &op1, mpz_size_t asize1,
int sign1,
unsigned long op2,
2333 const std::integral_constant<int, 0> &)
2335 using mppp_impl::copy_limbs;
2336 auto rdata = &rop.m_limbs[0];
2337 auto data1 = &op1.m_limbs[0];
2338 const auto size1 = op1._mp_size;
2339 const auto l2 =
static_cast<::mp_limb_t
>(op2);
2341 if (mppp_unlikely(!l2)) {
2342 rop._mp_size = size1;
2343 copy_limbs(data1, data1 + asize1, rdata);
2346 if (mppp_unlikely(!sign1)) {
2353 const bool c1 = std::size_t(asize1) == SSize && ((data1[asize1 - 1] & GMP_NUMB_MASK) >> (GMP_NUMB_BITS - 1));
2354 const bool c2 = SSize == 1u && (l2 >> (GMP_NUMB_BITS - 1));
2355 if (mppp_unlikely(c1 || c2)) {
2360 if (::mpn_add_1(rdata, data1, static_cast<::mp_size_t>(asize1), l2)) {
2361 assert(asize1 < s_int::s_size);
2362 rop._mp_size = size1 + 1;
2367 rop._mp_size = size1;
2371 if (asize1 > 1 || (asize1 == 1 && (data1[0] & GMP_NUMB_MASK) >= l2)) {
2373 const auto br = ::mpn_sub_1(rdata, data1, static_cast<::mp_size_t>(asize1), l2);
2377 rop._mp_size = size1 +
static_cast<mpz_size_t
>(!(rdata[asize1 - 1] & GMP_NUMB_MASK));
2380 const auto br = ::mpn_sub_1(rdata, &l2, 1, data1[0]);
2384 assert((rdata[0] & GMP_NUMB_MASK));
2391 static bool static_add_ui_impl(s_int &rop,
const s_int &op1, mpz_size_t,
int sign1,
unsigned long op2,
2392 const std::integral_constant<int, 1> &)
2394 using mppp_impl::limb_add_overflow;
2395 const auto l1 = op1.m_limbs[0];
2396 const auto l2 =
static_cast<::mp_limb_t
>(op2);
2400 if (mppp_unlikely(limb_add_overflow(l1, l2, &tmp))) {
2403 rop._mp_size = (tmp != 0u);
2404 rop.m_limbs[0] = tmp;
2411 rop._mp_size = -
static_cast<mpz_size_t
>(tmp != 0u);
2412 rop.m_limbs[0] = tmp;
2416 rop.m_limbs[0] = l2 - l1;
2422 static bool static_add_ui_impl(s_int &rop,
const s_int &op1, mpz_size_t asize1,
int sign1,
unsigned long op2,
2423 const std::integral_constant<int, 2> &)
2425 using mppp_impl::limb_add_overflow;
2426 auto rdata = &rop.m_limbs[0];
2427 auto data1 = &op1.m_limbs[0];
2428 const auto l2 =
static_cast<::mp_limb_t
>(op2);
2434 const ::mp_limb_t cy_lo = limb_add_overflow(data1[0], l2, &lo);
2436 const ::mp_limb_t cy_hi = limb_add_overflow(data1[1], cy_lo, &hi);
2437 if (mppp_unlikely(cy_hi)) {
2441 rop._mp_size = hi ? 2 : (lo ? 1 : 0);
2447 if (asize1 == 2 || data1[0] >= l2) {
2449 const auto lo = data1[0] - l2;
2451 const auto hi = data1[1] -
static_cast<::mp_limb_t
>(data1[0] < l2);
2453 rop._mp_size = hi ? -2 : (lo ? -1 : 0);
2460 rdata[0] = l2 - data1[0];
2466 static bool static_add_ui(s_int &rop,
const s_int &op1,
unsigned long op2)
2468 mpz_size_t asize1 = op1._mp_size;
2469 int sign1 = asize1 != 0;
2474 const bool retval = static_add_ui_impl(rop, op1, asize1, sign1, op2, static_add_ui_algo<s_int>{});
2475 if (static_add_ui_algo<s_int>::value == 0 && retval) {
2478 rop.zero_unused_limbs();
2494 if (std::numeric_limits<unsigned long>::max() > GMP_NUMB_MASK) {
2503 if (mppp_likely(sr && s1)) {
2505 if (mppp_likely(static_add_ui(rop.m_int.g_st(), op1.m_int.g_st(), op2))) {
2510 rop.m_int.promote(SSize + 1u);
2512 ::mpz_add_ui(&rop.m_int.g_dy(), op1.
get_mpz_view(), op2);
2523 using have_dlimb_mul = std::integral_constant<bool,
2524 #if (defined(_MSC_VER) && defined(_WIN64) && (GMP_NUMB_BITS == 64)) || (defined(MPPP_UINT128) && (GMP_NUMB_BITS == 64)) 2525 !GMP_NAIL_BITS && std::numeric_limits<::mp_limb_t>::digits == 64
2526 #elif GMP_NUMB_BITS == 32 2528 && std::numeric_limits<std::uint_least64_t>::digits == 64
2529 && std::numeric_limits<::mp_limb_t>::digits == 32
2534 template <
typename SInt>
2535 using static_mul_algo = std::integral_constant<int, (SInt::s_size == 1 && have_dlimb_mul::value)
2537 : ((SInt::s_size == 2 && have_dlimb_mul::value) ? 2 : 0)>;
2541 static std::size_t static_mul_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asize1,
2542 mpz_size_t asize2,
int sign1,
int sign2,
const std::integral_constant<int, 0> &)
2544 using mppp_impl::copy_limbs_no;
2546 if (mppp_unlikely(!sign1 || !sign2)) {
2550 auto rdata = &rop.m_limbs[0];
2551 auto data1 = &op1.m_limbs[0], data2 = &op2.m_limbs[0];
2552 const auto max_asize = std::size_t(asize1 + asize2);
2554 std::array<::mp_limb_t, SSize * 2u> res;
2558 ::mp_limb_t *MPPP_RESTRICT res_data
2559 = (rdata != data1 && rdata != data2 && max_asize <= SSize) ? rdata : res.data();
2564 hi = ::mpn_mul_1(res_data, data1, static_cast<::mp_size_t>(asize1), data2[0]);
2565 res_data[asize1] = hi;
2566 }
else if (asize1 == 1) {
2567 hi = ::mpn_mul_1(res_data, data2, static_cast<::mp_size_t>(asize2), data1[0]);
2568 res_data[asize2] = hi;
2569 }
else if (asize1 == asize2) {
2570 ::mpn_mul_n(res_data, data1, data2, static_cast<::mp_size_t>(asize1));
2571 hi = res_data[2 * asize1 - 1];
2572 }
else if (asize1 >= asize2) {
2573 hi = ::mpn_mul(res_data, data1, static_cast<::mp_size_t>(asize1), data2, static_cast<::mp_size_t>(asize2));
2575 hi = ::mpn_mul(res_data, data2, static_cast<::mp_size_t>(asize2), data1, static_cast<::mp_size_t>(asize1));
2578 const std::size_t asize = max_asize - unsigned(hi == 0u);
2579 if (res_data == rdata) {
2581 rop._mp_size = mpz_size_t(asize);
2582 if (sign1 != sign2) {
2583 rop._mp_size = -rop._mp_size;
2588 if (asize > SSize) {
2593 rop._mp_size = mpz_size_t(asize);
2594 if (sign1 != sign2) {
2595 rop._mp_size = -rop._mp_size;
2597 copy_limbs_no(res_data, res_data + asize, rdata);
2600 #if defined(_MSC_VER) && defined(_WIN64) && (GMP_NUMB_BITS == 64) && !GMP_NAIL_BITS 2601 static ::mp_limb_t dlimb_mul(::mp_limb_t op1, ::mp_limb_t op2, ::mp_limb_t *hi)
2603 return ::UnsignedMultiply128(op1, op2, hi);
2605 #elif defined(MPPP_UINT128) && (GMP_NUMB_BITS == 64) && !GMP_NAIL_BITS 2606 static ::mp_limb_t dlimb_mul(::mp_limb_t op1, ::mp_limb_t op2, ::mp_limb_t *hi)
2608 using dlimb_t = MPPP_UINT128;
2609 const dlimb_t res = dlimb_t(op1) * op2;
2610 *hi =
static_cast<::mp_limb_t
>(res >> 64);
2611 return static_cast<::mp_limb_t
>(res);
2613 #elif GMP_NUMB_BITS == 32 && !GMP_NAIL_BITS 2614 static ::mp_limb_t dlimb_mul(::mp_limb_t op1, ::mp_limb_t op2, ::mp_limb_t *hi)
2616 using dlimb_t = std::uint_least64_t;
2617 const dlimb_t res = dlimb_t(op1) * op2;
2618 *hi =
static_cast<::mp_limb_t
>(res >> 32);
2619 return static_cast<::mp_limb_t
>(res);
2623 static std::size_t static_mul_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t, mpz_size_t,
2624 int sign1,
int sign2,
const std::integral_constant<int, 1> &)
2627 const ::mp_limb_t lo = dlimb_mul(op1.m_limbs[0], op2.m_limbs[0], &hi);
2628 if (mppp_unlikely(hi)) {
2631 const mpz_size_t asize = (lo != 0u);
2632 rop._mp_size = asize;
2633 if (sign1 != sign2) {
2634 rop._mp_size = -rop._mp_size;
2636 rop.m_limbs[0] = lo;
2640 static std::size_t static_mul_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asize1,
2641 mpz_size_t asize2,
int sign1,
int sign2,
const std::integral_constant<int, 2> &)
2643 using mppp_impl::limb_add_overflow;
2644 if (mppp_unlikely(!asize1 || !asize2)) {
2647 rop.m_limbs[0] = 0u;
2648 rop.m_limbs[1] = 0u;
2651 if (asize1 == 1 && asize2 == 1) {
2652 rop.m_limbs[0] = dlimb_mul(op1.m_limbs[0], op2.m_limbs[0], &rop.m_limbs[1]);
2653 rop._mp_size =
static_cast<mpz_size_t
>((asize1 + asize2) - mpz_size_t(rop.m_limbs[1] == 0u));
2654 if (sign1 != sign2) {
2655 rop._mp_size = -rop._mp_size;
2659 if (asize1 != asize2) {
2667 ::mp_limb_t a = op1.m_limbs[0], b = op1.m_limbs[1], c = op2.m_limbs[0];
2668 if (asize1 < asize2) {
2670 a = op2.m_limbs[0], b = op2.m_limbs[1], c = op1.m_limbs[0];
2672 ::mp_limb_t ca_lo, ca_hi, cb_lo, cb_hi, tmp0, tmp1, tmp2;
2673 ca_lo = dlimb_mul(c, a, &ca_hi);
2674 cb_lo = dlimb_mul(c, b, &cb_hi);
2676 const auto cy = limb_add_overflow(cb_lo, ca_hi, &tmp1);
2679 const mpz_size_t asize = 2 + mpz_size_t(tmp2 != 0u);
2682 rop._mp_size = asize;
2683 if (sign1 != sign2) {
2684 rop._mp_size = -rop._mp_size;
2686 rop.m_limbs[0] = tmp0;
2687 rop.m_limbs[1] = tmp1;
2695 static std::size_t static_mul(s_int &rop,
const s_int &op1,
const s_int &op2)
2698 mpz_size_t asize1 = op1._mp_size, asize2 = op2._mp_size;
2699 int sign1 = asize1 != 0, sign2 = asize2 != 0;
2708 const std::size_t retval
2709 = static_mul_impl(rop, op1, op2, asize1, asize2, sign1, sign2, static_mul_algo<s_int>{});
2710 if (static_mul_algo<s_int>::value == 0 && retval == 0u) {
2711 rop.zero_unused_limbs();
2716 static mp_integer dispatch_binary_mul(
const mp_integer &op1,
const mp_integer &op2)
2719 mul(retval, op1, op2);
2722 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2723 static mp_integer dispatch_binary_mul(
const mp_integer &op1, T n)
2729 mul(retval, op1, mp_integer{n});
2732 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2733 static mp_integer dispatch_binary_mul(T n,
const mp_integer &op2)
2735 return dispatch_binary_mul(op2, n);
2737 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2738 static T dispatch_binary_mul(
const mp_integer &op1, T x)
2740 return static_cast<T
>(op1) * x;
2742 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2743 static T dispatch_binary_mul(T x,
const mp_integer &op2)
2745 return dispatch_binary_mul(op2, x);
2748 static void dispatch_in_place_mul(mp_integer &retval,
const mp_integer &n)
2750 mul(retval, retval, n);
2752 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
2753 static void dispatch_in_place_mul(mp_integer &retval,
const T &n)
2755 mul(retval, retval, mp_integer{n});
2757 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
2758 static void dispatch_in_place_mul(mp_integer &retval,
const T &x)
2760 retval =
static_cast<T
>(retval) * x;
2775 std::size_t size_hint = 0u;
2776 if (mppp_likely(sr && s1 && s2)) {
2777 size_hint = static_mul(rop.m_int.g_st(), op1.m_int.g_st(), op2.m_int.g_st());
2778 if (mppp_likely(size_hint == 0u)) {
2788 rop.m_int.promote(size_hint);
2799 template <
typename T,
typename U>
2802 return dispatch_binary_mul(op1, op2);
2813 template <
typename T, in_place_enabler<T> = 0>
2816 dispatch_in_place_mul(*
this, op);
2819 #if defined(_MSC_VER) 2820 template <
typename T>
2821 friend in_place_lenabler<T> operator*=(T &x,
const mp_integer &n)
2841 template <
typename T, in_place_lenabler<T> = 0>
2845 return x =
static_cast<T
>(x * n);
2851 template <
typename SInt>
2852 using static_addmul_algo
2853 = std::integral_constant<int,
2854 (static_add_algo<SInt>::value == 2 && static_mul_algo<SInt>::value == 2)
2856 : ((static_add_algo<SInt>::value == 1 && static_mul_algo<SInt>::value == 1) ? 1
2859 static std::size_t static_addmul_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asizer,
2860 mpz_size_t asize1, mpz_size_t asize2,
int signr,
int sign1,
int sign2,
2861 const std::integral_constant<int, 0> &)
2866 static_mul_impl(prod, op1, op2, asize1, asize2, sign1, sign2, std::integral_constant<int, 0>{}))) {
2868 return SSize * 2u + 1u;
2871 mpz_size_t asize_prod = prod._mp_size;
2872 int sign_prod = (asize_prod != 0);
2873 if (asize_prod < 0) {
2874 asize_prod = -asize_prod;
2878 if (mppp_unlikely(!static_add_impl(rop, rop, prod, asizer, asize_prod, signr, sign_prod,
2879 std::integral_constant<int, 0>{}))) {
2884 static std::size_t static_addmul_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t, mpz_size_t,
2885 mpz_size_t,
int signr,
int sign1,
int sign2,
2886 const std::integral_constant<int, 1> &)
2888 using mppp_impl::limb_add_overflow;
2891 const ::mp_limb_t prod = dlimb_mul(op1.m_limbs[0], op2.m_limbs[0], &tmp);
2892 if (mppp_unlikely(tmp)) {
2896 int sign_prod = prod != 0u;
2897 if (sign1 != sign2) {
2898 sign_prod = -sign_prod;
2901 if (signr == sign_prod) {
2903 if (mppp_unlikely(limb_add_overflow(rop.m_limbs[0], prod, &tmp))) {
2907 rop._mp_size = signr;
2908 rop.m_limbs[0] = tmp;
2911 if (rop.m_limbs[0] >= prod) {
2913 tmp = rop.m_limbs[0] - prod;
2915 rop._mp_size = signr;
2916 if (mppp_unlikely(!tmp)) {
2919 rop.m_limbs[0] = tmp;
2922 rop._mp_size = sign_prod;
2923 rop.m_limbs[0] = prod - rop.m_limbs[0];
2928 static std::size_t static_addmul_impl(s_int &rop,
const s_int &op1,
const s_int &op2, mpz_size_t asizer,
2929 mpz_size_t asize1, mpz_size_t asize2,
int signr,
int sign1,
int sign2,
2930 const std::integral_constant<int, 2> &)
2932 using mppp_impl::limb_add_overflow;
2933 if (mppp_unlikely(!asize1 || !asize2)) {
2938 std::array<::mp_limb_t, 2> prod;
2940 if (sign1 != sign2) {
2943 mpz_size_t asize_prod;
2944 if (asize1 == 1 && asize2 == 1) {
2945 prod[0] = dlimb_mul(op1.m_limbs[0], op2.m_limbs[0], &prod[1]);
2946 asize_prod = (asize1 + asize2) - mpz_size_t(prod[1] == 0u);
2955 if (mppp_unlikely(asize1 == asize2)) {
2959 ::mp_limb_t a = op1.m_limbs[0], b = op1.m_limbs[1], c = op2.m_limbs[0];
2960 if (asize1 < asize2) {
2962 a = op2.m_limbs[0], b = op2.m_limbs[1], c = op1.m_limbs[0];
2964 ::mp_limb_t ca_hi, cb_hi;
2966 prod[0] = dlimb_mul(c, a, &ca_hi);
2967 prod[1] = dlimb_mul(c, b, &cb_hi);
2970 const auto cy = limb_add_overflow(prod[1], ca_hi, &prod[1]);
2972 if (mppp_unlikely(cb_hi || cy)) {
2978 if (signr == sign_prod) {
2980 ::mp_limb_t lo, hi1, hi2;
2981 const ::mp_limb_t cy_lo = limb_add_overflow(rop.m_limbs[0], prod[0], &lo),
2982 cy_hi1 = limb_add_overflow(rop.m_limbs[1], prod[1], &hi1),
2983 cy_hi2 = limb_add_overflow(hi1, cy_lo, &hi2);
2985 if (mppp_unlikely(cy_hi1 || cy_hi2)) {
2992 rop._mp_size = signr;
2994 rop._mp_size = signr + signr;
2996 rop.m_limbs[0] = lo;
2997 rop.m_limbs[1] = hi2;
3000 if (asizer > asize_prod
3001 || (asizer == asize_prod && compare_limbs_2(&rop.m_limbs[0], &prod[0], asizer) >= 0)) {
3003 const auto lo = rop.m_limbs[0] - prod[0];
3005 assert(rop.m_limbs[0] >= prod[0] || rop.m_limbs[1] > prod[1]);
3007 const auto hi = rop.m_limbs[1] - prod[1] -
static_cast<::mp_limb_t
>(rop.m_limbs[0] < prod[0]);
3011 rop._mp_size = signr + signr;
3013 rop._mp_size = signr;
3015 rop.m_limbs[0] = lo;
3016 rop.m_limbs[1] = hi;
3019 const auto lo = prod[0] - rop.m_limbs[0];
3020 assert(prod[0] >= rop.m_limbs[0] || prod[1] > rop.m_limbs[1]);
3021 const auto hi = prod[1] - rop.m_limbs[1] -
static_cast<::mp_limb_t
>(prod[0] < rop.m_limbs[0]);
3023 rop._mp_size = sign_prod;
3025 rop._mp_size = sign_prod + sign_prod;
3027 rop.m_limbs[0] = lo;
3028 rop.m_limbs[1] = hi;
3033 static std::size_t static_addmul(s_int &rop,
const s_int &op1,
const s_int &op2)
3035 mpz_size_t asizer = rop._mp_size, asize1 = op1._mp_size, asize2 = op2._mp_size;
3036 int signr = asizer != 0, sign1 = asize1 != 0, sign2 = asize2 != 0;
3049 const std::size_t retval = static_addmul_impl(rop, op1, op2, asizer, asize1, asize2, signr, sign1, sign2,
3050 static_addmul_algo<s_int>{});
3051 if (static_addmul_algo<s_int>::value == 0 && retval == 0u) {
3052 rop.zero_unused_limbs();
3069 std::size_t size_hint = 0u;
3070 if (mppp_likely(sr && s1 && s2)) {
3071 size_hint = static_addmul(rop.m_int.g_st(), op1.m_int.g_st(), op2.m_int.g_st());
3072 if (mppp_likely(size_hint == 0u)) {
3077 rop.m_int.promote(size_hint);
3087 using have_dlimb_div = std::integral_constant<bool,
3088 #if defined(MPPP_UINT128) && (GMP_NUMB_BITS == 64) 3089 !GMP_NAIL_BITS && std::numeric_limits<::mp_limb_t>::digits == 64
3090 #elif GMP_NUMB_BITS == 32 3092 && std::numeric_limits<std::uint_least64_t>::digits == 64
3093 && std::numeric_limits<::mp_limb_t>::digits == 32
3102 template <
typename SInt>
3103 using static_div_algo
3104 = std::integral_constant<int, SInt::s_size == 1 ? 1 : ((SInt::s_size == 2 && have_dlimb_div::value) ? 2 : 0)>;
3106 static void static_div_impl(s_int &q, s_int &r,
const s_int &op1,
const s_int &op2, mpz_size_t asize1,
3107 mpz_size_t asize2,
int sign1,
int sign2,
const std::integral_constant<int, 0> &)
3109 using mppp_impl::copy_limbs_no;
3112 if (asize2 > asize1) {
3121 std::array<::mp_limb_t, SSize> op1_alt, op2_alt;
3122 const ::mp_limb_t *data1 = op1.m_limbs.data();
3123 const ::mp_limb_t *data2 = op2.m_limbs.data();
3124 if (&op1 == &q || &op1 == &r) {
3125 copy_limbs_no(data1, data1 + asize1, op1_alt.data());
3126 data1 = op1_alt.data();
3128 if (&op2 == &q || &op2 == &r || &op1 == &op2) {
3129 copy_limbs_no(data2, data2 + asize2, op2_alt.data());
3130 data2 = op2_alt.data();
3133 auto distinct_op = [&q, &r, data1, data2]() ->
bool {
3134 const ::mp_limb_t *ptrs[] = {q.m_limbs.data(), r.m_limbs.data(), data1, data2};
3135 std::sort(ptrs, ptrs + 4, std::less<const ::mp_limb_t *>());
3136 return std::unique(ptrs, ptrs + 4) == (ptrs + 4);
3139 assert(distinct_op());
3144 = ::mpn_divrem_1(q.m_limbs.data(), ::mp_size_t(0), data1,
static_cast<::mp_size_t
>(asize1), data2[0]);
3147 ::mpn_tdiv_qr(q.m_limbs.data(), r.m_limbs.data(), ::mp_size_t(0), data1,
static_cast<::mp_size_t
>(asize1),
3148 data2, static_cast<::mp_size_t>(asize2));
3151 q._mp_size = asize1 - asize2 + 1;
3152 while (q._mp_size && !(q.m_limbs[static_cast<std::size_t>(q._mp_size - 1)] & GMP_NUMB_MASK)) {
3155 if (sign1 != sign2) {
3156 q._mp_size = -q._mp_size;
3159 r._mp_size = asize2;
3160 while (r._mp_size && !(r.m_limbs[static_cast<std::size_t>(r._mp_size - 1)] & GMP_NUMB_MASK)) {
3164 r._mp_size = -r._mp_size;
3168 static void static_div_impl(s_int &q, s_int &r,
const s_int &op1,
const s_int &op2, mpz_size_t, mpz_size_t,
3169 int sign1,
int sign2,
const std::integral_constant<int, 1> &)
3175 const ::mp_limb_t q_ = (op1.m_limbs[0] & GMP_NUMB_MASK) / (op2.m_limbs[0] & GMP_NUMB_MASK),
3176 r_ = (op1.m_limbs[0] & GMP_NUMB_MASK) % (op2.m_limbs[0] & GMP_NUMB_MASK);
3178 q._mp_size = (q_ != 0u);
3179 if (sign1 != sign2) {
3180 q._mp_size = -q._mp_size;
3185 r._mp_size = (r_ != 0u);
3189 r._mp_size = -r._mp_size;
3193 #if defined(MPPP_UINT128) && (GMP_NUMB_BITS == 64) && !GMP_NAIL_BITS 3194 static void dlimb_div(::mp_limb_t op11, ::mp_limb_t op12, ::mp_limb_t op21, ::mp_limb_t op22,
3195 ::mp_limb_t *MPPP_RESTRICT q1, ::mp_limb_t *MPPP_RESTRICT q2, ::mp_limb_t *MPPP_RESTRICT r1,
3196 ::mp_limb_t *MPPP_RESTRICT r2)
3198 using dlimb_t = MPPP_UINT128;
3199 const auto op1 = op11 + (dlimb_t(op12) << 64);
3200 const auto op2 = op21 + (dlimb_t(op22) << 64);
3201 const auto q = op1 / op2, r = op1 % op2;
3202 *q1 =
static_cast<::mp_limb_t
>(q & ::mp_limb_t(-1));
3203 *q2 =
static_cast<::mp_limb_t
>(q >> 64);
3204 *r1 =
static_cast<::mp_limb_t
>(r & ::mp_limb_t(-1));
3205 *r2 =
static_cast<::mp_limb_t
>(r >> 64);
3208 static void dlimb_div(::mp_limb_t op11, ::mp_limb_t op12, ::mp_limb_t op21, ::mp_limb_t op22,
3209 ::mp_limb_t *MPPP_RESTRICT q1, ::mp_limb_t *MPPP_RESTRICT q2)
3211 using dlimb_t = MPPP_UINT128;
3212 const auto op1 = op11 + (dlimb_t(op12) << 64);
3213 const auto op2 = op21 + (dlimb_t(op22) << 64);
3214 const auto q = op1 / op2;
3215 *q1 =
static_cast<::mp_limb_t
>(q & ::mp_limb_t(-1));
3216 *q2 =
static_cast<::mp_limb_t
>(q >> 64);
3218 #elif GMP_NUMB_BITS == 32 && !GMP_NAIL_BITS 3219 static void dlimb_div(::mp_limb_t op11, ::mp_limb_t op12, ::mp_limb_t op21, ::mp_limb_t op22,
3220 ::mp_limb_t *MPPP_RESTRICT q1, ::mp_limb_t *MPPP_RESTRICT q2, ::mp_limb_t *MPPP_RESTRICT r1,
3221 ::mp_limb_t *MPPP_RESTRICT r2)
3223 using dlimb_t = std::uint_least64_t;
3224 const auto op1 = op11 + (dlimb_t(op12) << 32);
3225 const auto op2 = op21 + (dlimb_t(op22) << 32);
3226 const auto q = op1 / op2, r = op1 % op2;
3227 *q1 =
static_cast<::mp_limb_t
>(q & ::mp_limb_t(-1));
3228 *q2 =
static_cast<::mp_limb_t
>(q >> 32);
3229 *r1 =
static_cast<::mp_limb_t
>(r & ::mp_limb_t(-1));
3230 *r2 =
static_cast<::mp_limb_t
>(r >> 32);
3232 static void dlimb_div(::mp_limb_t op11, ::mp_limb_t op12, ::mp_limb_t op21, ::mp_limb_t op22,
3233 ::mp_limb_t *MPPP_RESTRICT q1, ::mp_limb_t *MPPP_RESTRICT q2)
3235 using dlimb_t = std::uint_least64_t;
3236 const auto op1 = op11 + (dlimb_t(op12) << 32);
3237 const auto op2 = op21 + (dlimb_t(op22) << 32);
3238 const auto q = op1 / op2;
3239 *q1 =
static_cast<::mp_limb_t
>(q & ::mp_limb_t(-1));
3240 *q2 =
static_cast<::mp_limb_t
>(q >> 32);
3244 static void static_div_impl(s_int &q, s_int &r,
const s_int &op1,
const s_int &op2, mpz_size_t asize1,
3245 mpz_size_t asize2,
int sign1,
int sign2,
const std::integral_constant<int, 2> &)
3247 if (asize1 < 2 && asize2 < 2) {
3251 const ::mp_limb_t q_ = op1.m_limbs[0] / op2.m_limbs[0], r_ = op1.m_limbs[0] % op2.m_limbs[0];
3252 q._mp_size = (q_ != 0u);
3253 if (sign1 != sign2) {
3254 q._mp_size = -q._mp_size;
3258 r._mp_size = (r_ != 0u);
3260 r._mp_size = -r._mp_size;
3267 ::mp_limb_t q1, q2, r1, r2;
3268 dlimb_div(op1.m_limbs[0], op1.m_limbs[1], op2.m_limbs[0], op2.m_limbs[1], &q1, &q2, &r1, &r2);
3270 q._mp_size = q2 ? 2 : (q1 ? 1 : 0);
3271 if (sign1 != sign2) {
3272 q._mp_size = -q._mp_size;
3276 r._mp_size = r2 ? 2 : (r1 ? 1 : 0);
3278 r._mp_size = -r._mp_size;
3283 static void static_div(s_int &q, s_int &r,
const s_int &op1,
const s_int &op2)
3285 mpz_size_t asize1 = op1._mp_size, asize2 = op2._mp_size;
3286 int sign1 = asize1 != 0, sign2 = asize2 != 0;
3295 static_div_impl(q, r, op1, op2, asize1, asize2, sign1, sign2, static_div_algo<s_int>{});
3296 if (static_div_algo<s_int>::value == 0) {
3297 q.zero_unused_limbs();
3298 r.zero_unused_limbs();
3302 static mp_integer dispatch_binary_div(
const mp_integer &op1,
const mp_integer &op2)
3305 tdiv_qr(retval, r, op1, op2);
3308 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
3309 static mp_integer dispatch_binary_div(
const mp_integer &op1, T n)
3312 tdiv_qr(retval, r, op1, mp_integer{n});
3315 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
3316 static mp_integer dispatch_binary_div(T n,
const mp_integer &op2)
3319 tdiv_qr(retval, r, mp_integer{n}, op2);
3322 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
3323 static T dispatch_binary_div(
const mp_integer &op1, T x)
3325 return static_cast<T
>(op1) / x;
3327 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
3328 static T dispatch_binary_div(T x,
const mp_integer &op2)
3330 return x /
static_cast<T
>(op2);
3333 static void dispatch_in_place_div(mp_integer &retval,
const mp_integer &n)
3336 tdiv_qr(retval, r, retval, n);
3338 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
3339 static void dispatch_in_place_div(mp_integer &retval,
const T &n)
3342 tdiv_qr(retval, r, retval, mp_integer{n});
3344 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
3345 static void dispatch_in_place_div(mp_integer &retval,
const T &x)
3347 retval =
static_cast<T
>(retval) / x;
3350 template <
typename T,
typename U>
3352 = enable_if_t<conjunction<negation<std::is_floating_point<T>>, negation<std::is_floating_point<U>>>::value,
3354 template <
typename T>
3355 using in_place_mod_enabler
3356 = enable_if_t<disjunction<is_supported_integral<T>, std::is_same<T, mp_integer>>::value,
int>;
3358 static mp_integer dispatch_binary_mod(
const mp_integer &op1,
const mp_integer &op2)
3361 tdiv_qr(q, retval, op1, op2);
3364 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
3365 static mp_integer dispatch_binary_mod(
const mp_integer &op1, T n)
3368 tdiv_qr(q, retval, op1, mp_integer{n});
3371 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
3372 static mp_integer dispatch_binary_mod(T n,
const mp_integer &op2)
3375 tdiv_qr(q, retval, mp_integer{n}, op2);
3379 static void dispatch_in_place_mod(mp_integer &retval,
const mp_integer &n)
3382 tdiv_qr(q, retval, retval, n);
3384 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
3385 static void dispatch_in_place_mod(mp_integer &retval,
const T &n)
3388 tdiv_qr(q, retval, retval, mp_integer{n});
3407 if (mppp_unlikely(&q == &r)) {
3408 throw std::invalid_argument(
"When performing a division with remainder, the quotient 'q' and the " 3409 "remainder 'r' must be distinct objects");
3411 if (mppp_unlikely(d.
sgn() == 0)) {
3415 if (mppp_likely(sq && sr && s1 && s2)) {
3416 static_div(q.m_int.g_st(), r.m_int.g_st(), n.m_int.g_st(), d.m_int.g_st());
3437 template <
typename T,
typename U>
3440 return dispatch_binary_div(n, d);
3452 template <
typename T, in_place_enabler<T> = 0>
3455 dispatch_in_place_div(*
this, d);
3458 #if defined(_MSC_VER) 3459 template <
typename T>
3460 friend in_place_lenabler<T> operator/=(T &x,
const mp_integer &n)
3481 template <
typename T, in_place_lenabler<T> = 0>
3485 return x =
static_cast<T
>(x / n);
3496 template <
typename T,
typename U>
3499 return dispatch_binary_mod(n, d);
3509 template <
typename T, in_place_mod_enabler<T> = 0>
3512 dispatch_in_place_mod(*
this, d);
3518 template <
typename SInt>
3519 using static_mul_2exp_algo = std::integral_constant<int, SInt::s_size == 1 ? 1 : (SInt::s_size == 2 ? 2 : 0)>;
3521 static std::size_t static_mul_2exp_impl(s_int &rop,
const s_int &n, ::mp_bitcnt_t s,
3522 const std::integral_constant<int, 0> &)
3524 using mppp_impl::copy_limbs_no;
3525 mpz_size_t asize = n._mp_size;
3526 if (s == 0u || asize == 0) {
3532 int sign = asize != 0;
3539 const auto ls = s / GMP_NUMB_BITS, rs = s % GMP_NUMB_BITS;
3542 const mpz_size_t new_asize = asize +
static_cast<mpz_size_t
>(ls);
3543 if (std::size_t(new_asize) < SSize) {
3545 ::mp_limb_t ret = 0u;
3549 ret = ::mpn_lshift(rop.m_limbs.data() + ls, n.m_limbs.data(),
static_cast<::mp_size_t
>(asize),
3552 rop.m_limbs[std::size_t(new_asize)] = ret;
3558 assert(new_asize > asize);
3559 std::move_backward(n.m_limbs.begin(), n.m_limbs.begin() + asize, rop.m_limbs.begin() + new_asize);
3562 std::fill(rop.m_limbs.data(), rop.m_limbs.data() + ls, ::mp_limb_t(0));
3564 rop._mp_size = new_asize + (ret != 0u);
3566 rop._mp_size = -rop._mp_size;
3570 if (std::size_t(new_asize) == SSize) {
3573 std::array<::mp_limb_t, SSize> tmp;
3574 if (::mpn_lshift(tmp.data(), n.m_limbs.data(),
static_cast<::mp_size_t
>(asize),
unsigned(rs))) {
3579 copy_limbs_no(tmp.data(), tmp.data() + asize, rop.m_limbs.data() + ls);
3582 assert(new_asize > asize);
3583 std::move_backward(n.m_limbs.begin(), n.m_limbs.begin() + asize, rop.m_limbs.begin() + new_asize);
3586 std::fill(rop.m_limbs.data(), rop.m_limbs.data() + ls, ::mp_limb_t(0));
3588 rop._mp_size = new_asize;
3590 rop._mp_size = -rop._mp_size;
3596 return std::size_t(new_asize) + 1u;
3599 static std::size_t static_mul_2exp_impl(s_int &rop,
const s_int &n, ::mp_bitcnt_t s,
3600 const std::integral_constant<int, 1> &)
3602 const ::mp_limb_t l = n.m_limbs[0] & GMP_NUMB_MASK;
3603 if (s == 0u || l == 0u) {
3608 if (mppp_unlikely(s >= GMP_NUMB_BITS || (l >> (GMP_NUMB_BITS - s)))) {
3616 return std::size_t(s) / GMP_NUMB_BITS + 2u;
3619 rop.m_limbs[0] = l << s;
3621 rop._mp_size = n._mp_size;
3625 static std::size_t static_mul_2exp_impl(s_int &rop,
const s_int &n, ::mp_bitcnt_t s,
3626 const std::integral_constant<int, 2> &)
3628 mpz_size_t asize = n._mp_size;
3629 if (s == 0u || asize == 0) {
3633 int sign = asize != 0;
3639 static_assert(GMP_NUMB_BITS
3640 < std::numeric_limits<
typename std::decay<decltype(GMP_NUMB_BITS)>::type>::max() / 2u,
3642 if (mppp_unlikely(s >= 2u * GMP_NUMB_BITS)) {
3644 return std::size_t(s) / GMP_NUMB_BITS + 1u + std::size_t(asize);
3646 if (s == GMP_NUMB_BITS) {
3648 if (mppp_unlikely(asize == 2)) {
3652 rop.m_limbs[1u] = n.m_limbs[0u];
3653 rop.m_limbs[0u] = 0u;
3662 ::mp_limb_t lo = n.m_limbs[0u], hi = n.m_limbs[1u];
3663 if (s > GMP_NUMB_BITS) {
3664 if (mppp_unlikely(asize == 2)) {
3665 return std::size_t(s) / GMP_NUMB_BITS + 1u + std::size_t(asize);
3671 s =
static_cast<::mp_bitcnt_t
>(s - GMP_NUMB_BITS);
3675 assert(s > 0u && s < GMP_NUMB_BITS);
3676 if (mppp_unlikely((hi & GMP_NUMB_MASK) >> (GMP_NUMB_BITS - s))) {
3680 hi = ((hi & GMP_NUMB_MASK) << s) + ((lo & GMP_NUMB_MASK) >> (GMP_NUMB_BITS - s));
3683 lo = ((lo & GMP_NUMB_MASK) << s) & GMP_NUMB_MASK;
3685 rop.m_limbs[0u] = lo;
3686 rop.m_limbs[1u] = hi;
3688 rop._mp_size = 1 + (hi != 0u);
3690 rop._mp_size = -rop._mp_size;
3694 static std::size_t static_mul_2exp(s_int &rop,
const s_int &n, ::mp_bitcnt_t s)
3696 const std::size_t retval = static_mul_2exp_impl(rop, n, s, static_mul_2exp_algo<s_int>{});
3697 if (static_mul_2exp_algo<s_int>::value == 0 && retval == 0u) {
3698 rop.zero_unused_limbs();
3715 std::size_t size_hint = 0u;
3716 if (mppp_likely(sr && sn)) {
3717 size_hint = static_mul_2exp(rop.m_int.g_st(), n.m_int.g_st(), s);
3718 if (mppp_likely(size_hint == 0u)) {
3723 rop.m_int.promote(size_hint);
3725 ::mpz_mul_2exp(&rop.m_int.g_dy(), n.
get_mpz_view(), s);
3727 #if defined(_MSC_VER) 3728 template <
typename T>
3729 friend shift_op_enabler<T> operator<<(
const mp_integer &n, T s)
3740 template <
typename T, shift_op_enabler<T> = 0>
3745 mul_2exp(retval, n, cast_to_bitcnt(s));
3748 #if defined(_MSC_VER) 3749 template <
typename T>
3750 shift_op_enabler<T> &operator<<=(T s)
3760 template <
typename T, shift_op_enabler<T> = 0>
3764 mul_2exp(*
this, *
this, cast_to_bitcnt(s));
3770 template <
typename SInt>
3771 using static_tdiv_q_2exp_algo = std::integral_constant<int, SInt::s_size == 1 ? 1 : (SInt::s_size == 2 ? 2 : 0)>;
3773 static void static_tdiv_q_2exp_impl(s_int &rop,
const s_int &n, ::mp_bitcnt_t s,
3774 const std::integral_constant<int, 0> &)
3776 mpz_size_t asize = n._mp_size;
3777 if (s == 0u || asize == 0) {
3783 int sign = asize != 0;
3790 const auto ls = s / GMP_NUMB_BITS, rs = s % GMP_NUMB_BITS;
3791 if (ls >= std::size_t(asize)) {
3798 const mpz_size_t new_asize = asize -
static_cast<mpz_size_t
>(ls);
3802 ::mpn_rshift(rop.m_limbs.data(), n.m_limbs.data() + ls,
static_cast<::mp_size_t
>(new_asize),
unsigned(rs));
3809 std::move(n.m_limbs.begin() + ls, n.m_limbs.begin() + asize, rop.m_limbs.begin());
3812 rop._mp_size = new_asize - ((rop.m_limbs[std::size_t(new_asize - 1)] & GMP_NUMB_MASK) == 0u);
3814 rop._mp_size = -rop._mp_size;
3818 static void static_tdiv_q_2exp_impl(s_int &rop,
const s_int &n, ::mp_bitcnt_t s,
3819 const std::integral_constant<int, 1> &)
3821 const ::mp_limb_t l = n.m_limbs[0] & GMP_NUMB_MASK;
3822 if (s == 0u || l == 0u) {
3826 if (s >= GMP_NUMB_BITS) {
3829 rop.m_limbs[0] = 0u;
3833 const auto res = l >> s;
3835 rop._mp_size = res ? n._mp_size : 0;
3836 rop.m_limbs[0] = res;
3839 static void static_tdiv_q_2exp_impl(s_int &rop,
const s_int &n, ::mp_bitcnt_t s,
3840 const std::integral_constant<int, 2> &)
3842 mpz_size_t asize = n._mp_size;
3843 if (s == 0u || asize == 0) {
3847 int sign = asize != 0;
3853 static_assert(GMP_NUMB_BITS
3854 < std::numeric_limits<
typename std::decay<decltype(GMP_NUMB_BITS)>::type>::max() / 2u,
3856 if (s >= 2u * GMP_NUMB_BITS) {
3858 rop.m_limbs[0u] = 0u;
3859 rop.m_limbs[1u] = 0u;
3862 if (s >= GMP_NUMB_BITS) {
3865 const auto lo = (n.m_limbs[1u] & GMP_NUMB_MASK) >> (s - GMP_NUMB_BITS);
3869 rop._mp_size = lo ? sign : 0;
3870 rop.m_limbs[0u] = lo;
3871 rop.m_limbs[1u] = 0u;
3874 assert(s > 0u && s < GMP_NUMB_BITS);
3878 const auto tmp = ((n.m_limbs[1u] & GMP_NUMB_MASK) << (GMP_NUMB_BITS - s)) & GMP_NUMB_MASK;
3879 rop.m_limbs[0u] = ((n.m_limbs[0u] & GMP_NUMB_MASK) >> s) + tmp;
3880 rop.m_limbs[1u] = (n.m_limbs[1u] & GMP_NUMB_MASK) >> s;
3883 rop._mp_size = asize - ((rop.m_limbs[std::size_t(asize - 1)] & GMP_NUMB_MASK) == 0u);
3885 rop._mp_size = -rop._mp_size;
3888 static void static_tdiv_q_2exp(s_int &rop,
const s_int &n, ::mp_bitcnt_t s)
3890 static_tdiv_q_2exp_impl(rop, n, s, static_tdiv_q_2exp_algo<s_int>{});
3891 if (static_tdiv_q_2exp_algo<s_int>::value == 0) {
3892 rop.zero_unused_limbs();
3909 if (mppp_likely(sr && sn)) {
3910 static_tdiv_q_2exp(rop.m_int.g_st(), n.m_int.g_st(), s);
3914 rop.m_int.promote();
3916 ::mpz_tdiv_q_2exp(&rop.m_int.g_dy(), n.
get_mpz_view(), s);
3918 #if defined(_MSC_VER) 3919 template <
typename T>
3920 friend shift_op_enabler<T> operator>>(
const mp_integer &n, T s)
3931 template <
typename T, shift_op_enabler<T> = 0>
3936 tdiv_q_2exp(retval, n, cast_to_bitcnt(s));
3939 #if defined(_MSC_VER) 3940 template <
typename T>
3941 shift_op_enabler<T> &operator>>=(T s)
3951 template <
typename T, shift_op_enabler<T> = 0>
3955 tdiv_q_2exp(*
this, *
this, cast_to_bitcnt(s));
3961 template <
typename SInt>
3962 using static_cmp_algo = std::integral_constant<int, SInt::s_size == 1 ? 1 : (SInt::s_size == 2 ? 2 : 0)>;
3964 static int static_cmp(
const s_int &n1,
const s_int &n2,
const std::integral_constant<int, 0> &)
3966 if (n1._mp_size < n2._mp_size) {
3969 if (n2._mp_size < n1._mp_size) {
3973 const auto asize = n1._mp_size >= 0 ? n1._mp_size : -n1._mp_size;
3980 const int cmp_abs = ::mpn_cmp(n1.m_limbs.data(), n2.m_limbs.data(),
static_cast<::mp_size_t
>(asize));
3982 return (n1._mp_size >= 0) ? cmp_abs : -cmp_abs;
3985 static int static_cmp(
const s_int &n1,
const s_int &n2,
const std::integral_constant<int, 1> &)
3987 if (n1._mp_size < n2._mp_size) {
3990 if (n2._mp_size < n1._mp_size) {
3993 int cmp_abs = (n1.m_limbs[0u] & GMP_NUMB_MASK) > (n2.m_limbs[0u] & GMP_NUMB_MASK);
3995 cmp_abs = -
static_cast<int>((n1.m_limbs[0u] & GMP_NUMB_MASK) < (n2.m_limbs[0u] & GMP_NUMB_MASK));
3997 return (n1._mp_size >= 0) ? cmp_abs : -cmp_abs;
4000 static int static_cmp(
const s_int &n1,
const s_int &n2,
const std::integral_constant<int, 2> &)
4002 if (n1._mp_size < n2._mp_size) {
4005 if (n2._mp_size < n1._mp_size) {
4008 auto asize = n1._mp_size >= 0 ? n1._mp_size : -n1._mp_size;
4009 while (asize != 0) {
4011 if ((n1.m_limbs[std::size_t(asize)] & GMP_NUMB_MASK) > (n2.m_limbs[std::size_t(asize)] & GMP_NUMB_MASK)) {
4012 return (n1._mp_size >= 0) ? 1 : -1;
4014 if ((n1.m_limbs[std::size_t(asize)] & GMP_NUMB_MASK) < (n2.m_limbs[std::size_t(asize)] & GMP_NUMB_MASK)) {
4015 return (n1._mp_size >= 0) ? -1 : 1;
4022 static bool dispatch_equality(
const mp_integer &a,
const mp_integer &b)
4024 const mp_size_t size_a = a.m_int.m_st._mp_size, size_b = b.m_int.m_st._mp_size;
4025 if (size_a != size_b) {
4028 const ::mp_limb_t *ptr_a, *ptr_b;
4030 if (a.is_static()) {
4031 ptr_a = a.m_int.g_st().m_limbs.data();
4032 asize =
static_cast<std::size_t
>((size_a >= 0) ? size_a : -size_a);
4034 ptr_a = a.m_int.g_dy()._mp_d;
4035 asize = ::mpz_size(&a.m_int.g_dy());
4037 if (b.is_static()) {
4038 ptr_b = b.m_int.g_st().m_limbs.data();
4040 ptr_b = b.m_int.g_dy()._mp_d;
4043 = [](const ::mp_limb_t &l1, const ::mp_limb_t &l2) {
return (l1 & GMP_NUMB_MASK) == (l2 & GMP_NUMB_MASK); };
4044 #if defined(_MSC_VER) 4045 return std::equal(stdext::make_checked_array_iterator(ptr_a, asize),
4046 stdext::make_checked_array_iterator(ptr_a, asize) + asize,
4047 stdext::make_checked_array_iterator(ptr_b, asize), limb_cmp);
4049 return std::equal(ptr_a, ptr_a + asize, ptr_b, limb_cmp);
4052 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
4053 static bool dispatch_equality(
const mp_integer &a, T n)
4055 return dispatch_equality(a, mp_integer{n});
4057 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
4058 static bool dispatch_equality(T n,
const mp_integer &a)
4060 return dispatch_equality(a, n);
4062 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
4063 static bool dispatch_equality(
const mp_integer &a, T x)
4065 return static_cast<T
>(a) == x;
4067 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
4068 static bool dispatch_equality(T x,
const mp_integer &a)
4070 return dispatch_equality(a, x);
4073 static bool dispatch_less_than(
const mp_integer &a,
const mp_integer &b)
4075 return cmp(a, b) < 0;
4077 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
4078 static bool dispatch_less_than(
const mp_integer &a, T n)
4080 return dispatch_less_than(a, mp_integer{n});
4082 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
4083 static bool dispatch_less_than(T n,
const mp_integer &a)
4085 return dispatch_greater_than(a, mp_integer{n});
4087 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
4088 static bool dispatch_less_than(
const mp_integer &a, T x)
4090 return static_cast<T
>(a) < x;
4092 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
4093 static bool dispatch_less_than(T x,
const mp_integer &a)
4095 return dispatch_greater_than(a, x);
4098 static bool dispatch_greater_than(
const mp_integer &a,
const mp_integer &b)
4100 return cmp(a, b) > 0;
4102 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
4103 static bool dispatch_greater_than(
const mp_integer &a, T n)
4105 return dispatch_greater_than(a, mp_integer{n});
4107 template <typename T, enable_if_t<is_supported_integral<T>::value,
int> = 0>
4108 static bool dispatch_greater_than(T n,
const mp_integer &a)
4110 return dispatch_less_than(a, mp_integer{n});
4112 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
4113 static bool dispatch_greater_than(
const mp_integer &a, T x)
4115 return static_cast<T
>(a) > x;
4117 template <typename T, enable_if_t<is_supported_float<T>::value,
int> = 0>
4118 static bool dispatch_greater_than(T x,
const mp_integer &a)
4120 return dispatch_less_than(a, x);
4123 #if defined(_MSC_VER) 4124 template <
typename T,
typename U>
4125 using rel_enabler = enable_if_t<!std::is_same<void, common_t<T, U>>::value,
bool>;
4127 template <
typename T,
typename U>
4128 using rel_enabler = enable_if_t<!std::is_same<void, common_t<T, U>>::value,
int>;
4143 if (mppp_likely(s1 && s2)) {
4144 return static_cmp(op1.m_int.g_st(), op2.m_int.g_st(), static_cmp_algo<s_int>{});
4148 #if defined(_MSC_VER) 4149 template <
typename T,
typename U>
4150 friend rel_enabler<T, U> operator==(
const T &op1,
const U &op2)
4159 template <
typename T,
typename U, rel_enabler<T, U> = 0>
4163 return dispatch_equality(op1, op2);
4165 #if defined(_MSC_VER) 4166 template <
typename T,
typename U>
4167 friend rel_enabler<T, U> operator!=(
const T &op1,
const U &op2)
4176 template <
typename T,
typename U, rel_enabler<T, U> = 0>
4180 return !(op1 == op2);
4182 #if defined(_MSC_VER) 4183 template <
typename T,
typename U>
4184 friend rel_enabler<T, U> operator<(
const T &op1,
const U &op2)
4193 template <
typename T,
typename U, rel_enabler<T, U> = 0>
4197 return dispatch_less_than(op1, op2);
4199 #if defined(_MSC_VER) 4200 template <
typename T,
typename U>
4201 friend rel_enabler<T, U> operator>=(
const T &op1,
const U &op2)
4210 template <
typename T,
typename U, rel_enabler<T, U> = 0>
4214 return !(op1 < op2);
4216 #if defined(_MSC_VER) 4217 template <
typename T,
typename U>
4218 friend rel_enabler<T, U> operator>(
const T &op1,
const U &op2)
4227 template <
typename T,
typename U, rel_enabler<T, U> = 0>
4231 return dispatch_greater_than(op1, op2);
4233 #if defined(_MSC_VER) 4234 template <
typename T,
typename U>
4235 friend rel_enabler<T, U> operator<=(
const T &op1,
const U &op2)
4244 template <
typename T,
typename U, rel_enabler<T, U> = 0>
4248 return !(op1 > op2);
4261 MPPP_MAYBE_TLS mpz_raii tmp;
4265 ::mpz_pow_ui(&rop.m_int.g_dy(), base.
get_mpz_view(), exp);
4278 pow_ui(retval, base, exp);
4283 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4284 static bool exp_nonnegative(
const T &exp)
4288 static bool exp_nonnegative(
const mp_integer &exp)
4290 return exp.sgn() >= 0;
4292 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4293 static unsigned long exp_to_ulong(
const T &exp)
4295 assert(exp >= T(0));
4297 if (mppp_unlikely(
static_cast<typename std::make_unsigned<T>::type
>(exp)
4298 > std::numeric_limits<unsigned long>::max())) {
4299 throw std::overflow_error(
"Cannot convert the integral value " + std::to_string(exp)
4300 +
" to unsigned long: the value is too large.");
4302 return static_cast<unsigned long>(exp);
4304 static unsigned long exp_to_ulong(
const mp_integer &exp)
4307 return static_cast<unsigned long>(exp);
4308 }
catch (
const std::overflow_error &) {
4310 throw std::overflow_error(
"Cannot convert the integral value " + exp.to_string()
4311 +
" to unsigned long: the value is too large.");
4314 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4315 static bool base_is_zero(
const T &base)
4317 return base == T(0);
4319 static bool base_is_zero(
const mp_integer &base)
4321 return base.is_zero();
4323 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4324 static bool exp_is_odd(
const T &exp)
4326 return (exp % T(2)) != T(0);
4328 static bool exp_is_odd(
const mp_integer &exp)
4332 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4333 static std::string exp_to_string(
const T &exp)
4335 return std::to_string(exp);
4337 static std::string exp_to_string(
const mp_integer &exp)
4339 return exp.to_string();
4343 template <
typename T, enable_if_t<disjunction<std::is_same<T, mp_
integer>, std::is_
integral<T>>::value,
int> = 0>
4344 static mp_integer pow_impl(
const mp_integer &base,
const T &exp)
4347 if (exp_nonnegative(exp)) {
4348 pow_ui(rop, base, exp_to_ulong(exp));
4349 }
else if (mppp_unlikely(base_is_zero(base))) {
4351 throw zero_division_error(
"cannot raise zero to the negative power " + exp_to_string(exp));
4352 }
else if (base.is_one()) {
4355 }
else if (base.is_negative_one()) {
4356 if (exp_is_odd(exp)) {
4370 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4371 static mp_integer pow_impl(
const T &base,
const mp_integer &exp)
4373 return pow_impl(mp_integer{base}, exp);
4376 template <typename T, enable_if_t<std::is_floating_point<T>::value,
int> = 0>
4377 static T pow_impl(
const mp_integer &base,
const T &exp)
4379 return std::pow(static_cast<T>(base), exp);
4382 template <typename T, enable_if_t<std::is_floating_point<T>::value,
int> = 0>
4383 static T pow_impl(
const T &base,
const mp_integer &exp)
4385 return std::pow(base, static_cast<T>(exp));
4409 template <
typename T,
typename U>
4410 friend common_t<T, U>
pow(
const T &base,
const U &exp)
4412 return pow_impl(base, exp);
4423 if (m_int.g_st()._mp_size < 0) {
4424 m_int.g_st()._mp_size = -m_int.g_st()._mp_size;
4427 ::mpz_abs(&m_int.g_dy(), &m_int.g_dy());
4467 const mpz_size_t size = n.m_int.m_st._mp_size;
4468 const ::mp_limb_t *ptr;
4469 if (n.m_int.is_static()) {
4470 asize =
static_cast<std::size_t
>((size >= 0) ? size : -size);
4471 ptr = n.m_int.g_st().m_limbs.data();
4473 asize = ::mpz_size(&n.m_int.g_dy());
4474 ptr = n.m_int.g_dy()._mp_d;
4477 auto retval =
static_cast<std::size_t
>(size);
4479 for (std::size_t i = 0; i < asize; ++i) {
4482 retval ^= (ptr[i] & GMP_NUMB_MASK) + std::size_t(0x9e3779b9) + (retval << 6) + (retval >> 2);
4491 MPPP_MAYBE_TLS mpz_raii tmp;
4511 nextprime_impl(rop, n);
4522 nextprime_impl(retval, n);
4533 nextprime_impl(*
this, *
this);
4550 if (mppp_unlikely(reps < 1)) {
4551 throw std::invalid_argument(
"The number of primality tests must be at least 1, but a value of " 4552 + std::to_string(reps) +
" was provided instead");
4554 if (mppp_unlikely(sgn() < 0)) {
4555 throw std::invalid_argument(
"Cannot run primality tests on the negative number " + to_string());
4557 return ::mpz_probab_prime_p(get_mpz_view(), reps);
4578 using mppp_impl::copy_limbs_no;
4579 if (mppp_unlikely(n.m_int.m_st._mp_size < 0)) {
4580 throw std::domain_error(
"Cannot compute the square root of the negative number " + n.
to_string());
4583 if (mppp_likely(sr && sn)) {
4584 s_int &rs = rop.m_int.g_st();
4585 const s_int &ns = n.m_int.g_st();
4587 const mpz_size_t size = ns._mp_size;
4591 rs.zero_unused_limbs();
4595 std::array<::mp_limb_t, SSize> tmp;
4596 const bool overlap = (&rs == &ns);
4597 auto out_ptr = overlap ? tmp.data() : rs.m_limbs.data();
4598 ::mpn_sqrtrem(out_ptr,
nullptr, ns.m_limbs.data(),
static_cast<::mp_size_t
>(size));
4600 const mpz_size_t new_size = size / 2 + size % 2;
4601 assert(!new_size || (out_ptr[new_size - 1] & GMP_NUMB_MASK));
4603 rs._mp_size = new_size;
4605 copy_limbs_no(out_ptr, out_ptr + new_size, rs.m_limbs.data());
4608 rs.zero_unused_limbs();
4628 sqrt_impl(*
this, *
this);
4655 sqrt_impl(retval, n);
4666 return (m_int.g_st().m_limbs[0] & GMP_NUMB_MASK) & ::mp_limb_t(1);
4668 return mpz_odd_p(&m_int.g_dy());
4711 constexpr
auto max_fac = 1000000ull;
4712 if (mppp_unlikely(n > max_fac)) {
4713 throw std::invalid_argument(
4714 "The value " + std::to_string(n)
4715 +
" is too large to be used as input for the factorial function (the maximum allowed value is " 4716 + std::to_string(max_fac) +
")");
4719 MPPP_MAYBE_TLS mpz_raii tmp;
4720 ::mpz_fac_ui(&tmp.m_mpz, n);
4723 ::mpz_fac_ui(&rop.m_int.g_dy(), n);
4738 MPPP_MAYBE_TLS mpz_raii tmp;
4755 bin_ui(retval, n, k);
4760 template <
typename T,
typename U>
4761 using binomial_enabler_impl = std::
4762 integral_constant<bool, disjunction<conjunction<std::is_same<mp_integer, T>, std::is_same<mp_integer, U>>,
4763 conjunction<std::is_same<mp_integer, T>, is_supported_integral<U>>,
4764 conjunction<std::is_same<mp_integer, U>, is_supported_integral<T>>>::value>;
4765 #if defined(_MSC_VER) 4766 template <
typename T,
typename U>
4767 using binomial_enabler = enable_if_t<binomial_enabler_impl<T, U>::value,
mp_integer>;
4769 template <
typename T,
typename U>
4770 using binomial_enabler = enable_if_t<binomial_enabler_impl<T, U>::value,
int>;
4772 template <
typename T>
4776 if (exp_nonnegative(k)) {
4777 return bin_ui(n, exp_to_ulong(k));
4783 return mp_integer{};
4793 auto retval = bin_ui(tmp, exp_to_ulong(nmk));
4801 template <typename T, enable_if_t<std::is_integral<T>::value,
int> = 0>
4802 static mp_integer binomial_impl(
const T &n,
const mp_integer &k)
4804 return binomial_impl(mp_integer{n}, k);
4808 #if defined(_MSC_VER) 4809 template <
typename T,
typename U>
4810 friend binomial_enabler<T, U>
binomial(
const T &n,
const U &k)
4832 template <
typename T,
typename U, binomial_enabler<T, U> = 0>
4836 return binomial_impl(n, k);
4842 static void static_divexact_impl(s_int &q,
const s_int &op1,
const s_int &op2, mpz_size_t asize1, mpz_size_t asize2,
4843 int sign1,
int sign2,
const std::integral_constant<int, 0> &)
4845 using mppp_impl::copy_limbs_no;
4851 #if __GNU_MP_VERSION > 6 || (__GNU_MP_VERSION == 6 && __GNU_MP_VERSION_MINOR >= 1) 4856 ::mpn_divexact_1(q.m_limbs.data(), op1.m_limbs.data(),
static_cast<::mp_size_t
>(asize1), op2.m_limbs[0]);
4858 q._mp_size = asize1 - asize2 + 1;
4859 while (q._mp_size && !(q.m_limbs[static_cast<std::size_t>(q._mp_size - 1)] & GMP_NUMB_MASK)) {
4862 if (sign1 != sign2) {
4863 q._mp_size = -q._mp_size;
4874 MPPP_MAYBE_TLS mpz_raii tmp;
4875 ::mpz_divexact(&tmp.m_mpz, op1.get_mpz_view(), op2.get_mpz_view());
4877 q._mp_size = tmp.m_mpz._mp_size;
4878 copy_limbs_no(tmp.m_mpz._mp_d, tmp.m_mpz._mp_d + (q._mp_size >= 0 ? q._mp_size : -q._mp_size),
4882 static void static_divexact_impl(s_int &q,
const s_int &op1,
const s_int &op2, mpz_size_t, mpz_size_t,
int sign1,
4883 int sign2,
const std::integral_constant<int, 1> &)
4885 const ::mp_limb_t q_ = (op1.m_limbs[0] & GMP_NUMB_MASK) / (op2.m_limbs[0] & GMP_NUMB_MASK);
4887 q._mp_size = (q_ != 0u);
4888 if (sign1 != sign2) {
4889 q._mp_size = -q._mp_size;
4894 static void static_divexact_impl(s_int &q,
const s_int &op1,
const s_int &op2, mpz_size_t asize1, mpz_size_t asize2,
4895 int sign1,
int sign2,
const std::integral_constant<int, 2> &)
4897 if (asize1 < 2 && asize2 < 2) {
4899 const ::mp_limb_t q_ = op1.m_limbs[0] / op2.m_limbs[0];
4900 q._mp_size = (q_ != 0u);
4901 if (sign1 != sign2) {
4902 q._mp_size = -q._mp_size;
4910 dlimb_div(op1.m_limbs[0], op1.m_limbs[1], op2.m_limbs[0], op2.m_limbs[1], &q1, &q2);
4911 q._mp_size = q2 ? 2 : (q1 ? 1 : 0);
4912 if (sign1 != sign2) {
4913 q._mp_size = -q._mp_size;
4918 static void static_divexact(s_int &q,
const s_int &op1,
const s_int &op2)
4920 mpz_size_t asize1 = op1._mp_size, asize2 = op2._mp_size;
4921 int sign1 = asize1 != 0, sign2 = asize2 != 0;
4930 assert(asize1 == 0 || asize2 <= asize1);
4932 static_divexact_impl(q, op1, op2, asize1, asize2, sign1, sign2, static_div_algo<s_int>{});
4933 if (static_div_algo<s_int>::value == 0) {
4934 q.zero_unused_limbs();
4952 if (mppp_likely(sr && s1 && s2)) {
4953 static_divexact(rop.m_int.g_st(), n.m_int.g_st(), d.m_int.g_st());
4958 rop.m_int.promote();
4974 divexact(retval, n, d);
4979 static void static_gcd(s_int &rop,
const s_int &op1,
const s_int &op2)
4981 using mppp_impl::copy_limbs_no;
4982 mpz_size_t asize1 = op1._mp_size, asize2 = op2._mp_size;
4991 rop._mp_size = asize2;
4992 rop.m_limbs = op2.m_limbs;
4996 rop._mp_size = asize1;
4997 rop.m_limbs = op1.m_limbs;
5003 rop.m_limbs[0] = ::mpn_gcd_1(op2.m_limbs.data(),
static_cast<::mp_size_t
>(asize2), op1.m_limbs[0]);
5008 rop.m_limbs[0] = ::mpn_gcd_1(op1.m_limbs.data(),
static_cast<::mp_size_t
>(asize1), op2.m_limbs[0]);
5020 MPPP_MAYBE_TLS mpz_raii tmp;
5021 ::mpz_gcd(&tmp.m_mpz, op1.get_mpz_view(), op2.get_mpz_view());
5023 rop._mp_size = tmp.m_mpz._mp_size;
5024 assert(rop._mp_size > 0);
5025 copy_limbs_no(tmp.m_mpz._mp_d, tmp.m_mpz._mp_d + rop._mp_size, rop.m_limbs.data());
5041 if (mppp_likely(sr && s1 && s2)) {
5042 static_gcd(rop.m_int.g_st(), op1.m_int.g_st(), op2.m_int.g_st());
5043 rop.m_int.g_st().zero_unused_limbs();
5047 rop.m_int.promote();
5061 gcd(retval, op1, op2);
5098 return &m_int.g_dy();
5106 return m_int.m_st._mp_size == 0;
5122 bool is_one_impl()
const 5124 if (m_int.m_st._mp_size != One) {
5128 const ::mp_limb_t *ptr = is_static() ? m_int.g_st().m_limbs.data() : m_int.g_dy()._mp_d;
5129 return (ptr[0] & GMP_NUMB_MASK) == 1u;
5139 return is_one_impl<1>();
5157 return is_one_impl<-1>();
5171 mppp_impl::integer_union<SSize> m_int;
5174 template <std::
size_t SSize>
5175 constexpr std::size_t mp_integer<SSize>::ssize;
5181 template <
size_t SSize>
5182 inline std::size_t hash_wrapper(
const mp_integer<SSize> &n)
5193 template <
size_t SSize>
5194 struct hash<MPPP_NAMESPACE::mp_integer<SSize>> {
5207 return MPPP_NAMESPACE::mppp_impl::hash_wrapper(n);
5212 #if defined(_MSC_VER) 5214 #pragma warning(pop) mp_integer(const char *s, int base=10)
Constructor from C string.
bool demote()
Demote to static storage.
friend void sub(mp_integer &rop, const mp_integer &op1, const mp_integer &op2)
Ternary subtraction.
Multiprecision integer class.
friend T & operator+=(T &x, const mp_integer &n)
In-place addition for interoperable types.
friend mp_integer neg(const mp_integer &n)
Unary negation.
const mppp_impl::integer_union< SSize > & _get_union() const
Return a const reference to the internal union.
friend bool operator>=(const T &op1, const U &op2)
Greater-than or equal operator.
bool is_zero() const
Test if the value is zero.
friend int sgn(const mp_integer &n)
Sign function.
mp_integer & operator++()
Prefix increment.
friend mp_integer bin_ui(const mp_integer &n, unsigned long k)
Binomial coefficient (binary version).
mp_integer(const ::mpz_t n)
Constructor from mpz_t.
std::remove_extent<::mpz_t >::type * get_mpz_t()
Get a pointer to the dynamic storage.
friend void divexact(mp_integer &rop, const mp_integer &n, const mp_integer &d)
Exact division (ternary version).
friend mp_integer operator<<(const mp_integer &n, T s)
Left shift operator.
friend bool operator<(const T &op1, const U &op2)
Less-than operator.
friend void gcd(mp_integer &rop, const mp_integer &op1, const mp_integer &op2)
GCD (ternary version).
mp_integer & operator=(const T &x)
Generic assignment operator.
mp_integer & operator+=(const T &op)
In-place addition operator.
friend bool odd_p(const mp_integer &n)
Test if integer is odd.
friend mp_integer nextprime(const mp_integer &n)
Compute next prime number (unary version).
mp_integer & abs()
In-place absolute value.
friend void bin_ui(mp_integer &rop, const mp_integer &n, unsigned long k)
Binomial coefficient (ternary version).
std::string to_string(int base=10) const
Conversion to string.
friend mp_integer divexact(const mp_integer &n, const mp_integer &d)
Exact division (binary version).
friend void fac_ui(mp_integer &rop, unsigned long n)
Factorial.
friend common_t< T, U > operator-(const T &op1, const U &op2)
Binary subtraction operator.
mppp_impl::integer_union< SSize > & _get_union()
Return a reference to the internal union.
friend void addmul(mp_integer &rop, const mp_integer &op1, const mp_integer &op2)
Ternary multiply–accumulate.
friend T & operator*=(T &x, const mp_integer &n)
In-place multiplication for interoperable types.
friend common_t< T, U > operator*(const T &op1, const U &op2)
Binary multiplication operator.
bool promote()
Promote to dynamic storage.
friend std::istream & operator>>(std::istream &is, mp_integer &n)
Input stream operator for mp_integer.
friend T & operator-=(T &x, const mp_integer &n)
In-place subtraction for interoperable types.
friend bool even_p(const mp_integer &n)
Test if integer is even.
friend void abs(mp_integer &rop, const mp_integer &n)
Binary absolute value.
friend void nextprime(mp_integer &rop, const mp_integer &n)
Compute next prime number (binary version).
bool is_negative_one() const
Test if the value is equal to minus one.
mp_integer & operator>>=(T s)
In-place right shift operator.
friend void neg(mp_integer &rop, const mp_integer &n)
Binary negation.
friend int cmp(const mp_integer &op1, const mp_integer &op2)
Comparison function for mp_integer.
bool odd_p() const
Test if value is odd.
friend bool operator<=(const T &op1, const U &op2)
Less-than or equal operator.
mp_integer & nextprime()
Compute next prime number (in-place version).
mpz_view get_mpz_view() const
Get an mpz_t view.
mp_integer & neg()
Negate in-place.
mp_integer & operator--()
Prefix decrement.
friend common_t< T, U > pow(const T &base, const U &exp)
Generic binary exponentiation.
friend common_mod_t< T, U > operator%(const T &n, const U &d)
Binary modulo operator.
size_t result_type
The result type.
friend bool operator>(const T &op1, const U &op2)
Greater-than operator.
std::size_t size() const
Size in limbs.
std::size_t nbits() const
Size in bits.
mp_integer & operator/=(const T &d)
In-place division operator.
result_type operator()(const argument_type &n) const
Call operator.
mp_integer operator+() const
Identity operator.
int probab_prime_p(int reps=25) const
Test primality.
math_binomial_type< T, U > binomial(const T &x, const U &y)
Generalised binomial coefficient.
bool is_static() const
Test for static storage.
bool is_one() const
Test if the value is equal to one.
Exception to signal division by zero.
friend common_t< T, U > operator/(const T &n, const U &d)
Binary division operator.
friend std::size_t hash(const mp_integer &n)
Hash value.
friend void sqrt(mp_integer &rop, const mp_integer &n)
Integer square root (binary version).
mp_integer operator-() const
Negated copy.
bool even_p() const
Test if value is even.
friend mp_integer operator>>(const mp_integer &n, T s)
Right shift operator.
friend mp_integer gcd(const mp_integer &op1, const mp_integer &op2)
GCD (binary version).
mppp::mp_integer< SSize > argument_type
The argument type.
friend bool is_one(const mp_integer &n)
Test if an mppp::mp_integer is equal to one.
friend bool is_zero(const mp_integer &n)
Test if an mppp::mp_integer is zero.
mp_integer operator++(int)
Suffix increment.
friend void tdiv_qr(mp_integer &q, mp_integer &r, const mp_integer &n, const mp_integer &d)
Ternary truncated division.
friend mp_integer abs(const mp_integer &n)
Unary absolute value.
friend void add_ui(mp_integer &rop, const mp_integer &op1, unsigned long op2)
Ternary add with unsigned long.
friend mp_integer pow_ui(const mp_integer &base, unsigned long exp)
Binary exponentiation.
friend int probab_prime_p(const mp_integer &n, int reps=25)
Test primality.
mp_integer & operator%=(const T &d)
In-place modulo operator.
friend void mul(mp_integer &rop, const mp_integer &op1, const mp_integer &op2)
Ternary multiplication.
friend void add(mp_integer &rop, const mp_integer &op1, const mp_integer &op2)
Ternary add.
friend bool operator==(const T &op1, const U &op2)
Equality operator.
mppp::mp_integer< SSize > mp_integer
Alias for mppp::mp_integer.
mp_integer(T x)
Generic constructor.
mp_integer operator--(int)
Suffix decrement.
mp_integer & sqrt()
Integer square root (in-place version).
friend mp_integer sqrt(const mp_integer &n)
Integer square root (unary version).
mp_integer(const std::string &s, int base=10)
Constructor from C++ string (equivalent to the constructor from C string).
friend void pow_ui(mp_integer &rop, const mp_integer &base, unsigned long exp)
Ternary exponentiation.
friend T & operator/=(T &x, const mp_integer &n)
In-place division for interoperable types.
mp_integer & operator*=(const T &op)
In-place multiplication operator.
friend bool operator!=(const T &op1, const U &op2)
Inequality operator.
friend mp_integer binomial(const T &n, const U &k)
Generic binomial coefficient.
friend bool is_negative_one(const mp_integer &n)
Test if an mppp::mp_integer is equal to minus one.
friend common_t< T, U > operator+(const T &op1, const U &op2)
Binary addition operator.
mp_integer & operator<<=(T s)
In-place left shift operator.
friend std::ostream & operator<<(std::ostream &os, const mp_integer &n)
Output stream operator for mp_integer.
mp_integer & operator-=(const T &op)
In-place subtraction operator.
bool is_dynamic() const
Check for dynamic storage.
friend void mul_2exp(mp_integer &rop, const mp_integer &n, ::mp_bitcnt_t s)
Ternary left shift.
friend void tdiv_q_2exp(mp_integer &rop, const mp_integer &n, ::mp_bitcnt_t s)
Ternary right shift.