File indexing completed on 2025-07-11 08:17:29
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_MP_CPP_INT_MISC_HPP
0012 #define BOOST_MP_CPP_INT_MISC_HPP
0013
0014 #include <boost/multiprecision/detail/standalone_config.hpp>
0015 #include <boost/multiprecision/detail/number_base.hpp>
0016 #include <boost/multiprecision/cpp_int/cpp_int_config.hpp>
0017 #include <boost/multiprecision/detail/float128_functions.hpp>
0018 #include <boost/multiprecision/detail/assert.hpp>
0019 #include <boost/multiprecision/detail/constexpr.hpp>
0020 #include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
0021 #include <boost/multiprecision/detail/hash.hpp>
0022 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0023 #include <numeric> // std::gcd
0024 #include <type_traits>
0025 #include <stdexcept>
0026 #include <cmath>
0027
0028 #ifndef BOOST_MP_STANDALONE
0029 #include <boost/integer/common_factor_rt.hpp>
0030 #endif
0031
0032 #ifdef BOOST_MP_MATH_AVAILABLE
0033 #include <boost/math/special_functions/next.hpp>
0034 #endif
0035
0036 #ifdef BOOST_MSVC
0037 #pragma warning(push)
0038 #pragma warning(disable : 4702)
0039 #pragma warning(disable : 4127)
0040 #pragma warning(disable : 4146)
0041 #endif
0042
0043
0044 namespace boost { namespace multiprecision { namespace detail {
0045
0046 template <typename T>
0047 inline BOOST_CXX14_CONSTEXPR T constexpr_gcd(T a, T b) noexcept;
0048
0049 template <typename T>
0050 inline BOOST_CXX14_CONSTEXPR T constexpr_lcm(T a, T b) noexcept;
0051
0052 }}}
0053
0054 namespace boost { namespace multiprecision { namespace backends {
0055
0056 template <class T, bool has_limits = std::numeric_limits<T>::is_specialized>
0057 struct numeric_limits_workaround : public std::numeric_limits<T>
0058 {
0059 };
0060 template <class R>
0061 struct numeric_limits_workaround<R, false>
0062 {
0063 static constexpr unsigned digits = ~static_cast<R>(0) < 0 ? sizeof(R) * CHAR_BIT - 1 : sizeof(R) * CHAR_BIT;
0064 static constexpr R (min)(){ return (static_cast<R>(-1) < 0) ? static_cast<R>(1) << digits : 0; }
0065 static constexpr R (max)() { return (static_cast<R>(-1) < 0) ? ~(static_cast<R>(1) << digits) : ~static_cast<R>(0); }
0066 };
0067
0068 template <class R, class CppInt>
0069 BOOST_MP_CXX14_CONSTEXPR void check_in_range(const CppInt& val, const std::integral_constant<int, checked>&)
0070 {
0071 using cast_type = typename boost::multiprecision::detail::canonical<R, CppInt>::type;
0072
0073 if (val.sign())
0074 {
0075 BOOST_IF_CONSTEXPR (boost::multiprecision::detail::is_signed<R>::value == false)
0076 BOOST_MP_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
0077 if (val.compare(static_cast<cast_type>((numeric_limits_workaround<R>::min)())) < 0)
0078 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
0079 }
0080 else
0081 {
0082 if (val.compare(static_cast<cast_type>((numeric_limits_workaround<R>::max)())) > 0)
0083 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
0084 }
0085 }
0086 template <class R, class CppInt>
0087 inline BOOST_MP_CXX14_CONSTEXPR void check_in_range(const CppInt& , const std::integral_constant<int, unchecked>&) noexcept {}
0088
0089 inline BOOST_MP_CXX14_CONSTEXPR void check_is_negative(const std::integral_constant<bool, true>&) noexcept {}
0090 inline void check_is_negative(const std::integral_constant<bool, false>&)
0091 {
0092 BOOST_MP_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
0093 }
0094
0095 template <class Integer>
0096 inline BOOST_MP_CXX14_CONSTEXPR Integer negate_integer(Integer i, const std::integral_constant<bool, true>&) noexcept
0097 {
0098 return -i;
0099 }
0100 template <class Integer>
0101 inline BOOST_MP_CXX14_CONSTEXPR Integer negate_integer(Integer i, const std::integral_constant<bool, false>&) noexcept
0102 {
0103 return ~(i - 1);
0104 }
0105
0106 template <class R, std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0107 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
0108 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend)
0109 {
0110 using checked_type = std::integral_constant<int, Checked1>;
0111 check_in_range<R>(backend, checked_type());
0112
0113 BOOST_IF_CONSTEXPR(numeric_limits_workaround<R>::digits < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
0114 {
0115 if ((backend.sign() && boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value) && (1 + static_cast<boost::multiprecision::limb_type>((std::numeric_limits<R>::max)()) <= backend.limbs()[0]))
0116 {
0117 *result = (numeric_limits_workaround<R>::min)();
0118 return;
0119 }
0120 else if (boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value && !backend.sign() && static_cast<boost::multiprecision::limb_type>((std::numeric_limits<R>::max)()) <= backend.limbs()[0])
0121 {
0122 *result = (numeric_limits_workaround<R>::max)();
0123 return;
0124 }
0125 else
0126 *result = static_cast<R>(backend.limbs()[0]);
0127 }
0128 else
0129 *result = static_cast<R>(backend.limbs()[0]);
0130
0131 BOOST_IF_CONSTEXPR(numeric_limits_workaround<R>::digits > cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
0132 {
0133 std::size_t shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0134 std::size_t i = 1u;
0135
0136 while ((i < backend.size()) && (shift < static_cast<unsigned>(numeric_limits_workaround<R>::digits - cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)))
0137 {
0138 *result += static_cast<R>(backend.limbs()[i]) << shift;
0139 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0140 ++i;
0141 }
0142
0143
0144
0145 if (i < backend.size())
0146 {
0147 const limb_type mask = ((numeric_limits_workaround<R>::digits - shift) == cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits) ? ~static_cast<limb_type>(0) : static_cast<limb_type>(static_cast<limb_type>(1u) << (numeric_limits_workaround<R>::digits - shift)) - 1u;
0148 const limb_type limb_at_index_masked = static_cast<limb_type>(backend.limbs()[i] & mask);
0149
0150 *result = static_cast<R>(*result + static_cast<R>(static_cast<R>(limb_at_index_masked) << shift));
0151
0152 if ((backend.limbs()[i] & static_cast<limb_type>(~mask)) || (i + 1 < backend.size()))
0153 {
0154
0155 if (backend.sign())
0156 {
0157 check_is_negative(boost::multiprecision::detail::is_signed<R>());
0158 *result = (numeric_limits_workaround<R>::min)();
0159 }
0160 else if (boost::multiprecision::detail::is_signed<R>::value)
0161 *result = (numeric_limits_workaround<R>::max)();
0162 return;
0163 }
0164 }
0165 }
0166 else if (backend.size() > 1)
0167 {
0168
0169 if (backend.sign())
0170 {
0171 check_is_negative(boost::multiprecision::detail::is_signed<R>());
0172 *result = (numeric_limits_workaround<R>::min)();
0173 }
0174 else if (boost::multiprecision::detail::is_signed<R>::value)
0175 *result = (numeric_limits_workaround<R>::max)();
0176 return;
0177 }
0178 if (backend.sign())
0179 {
0180 check_is_negative(std::integral_constant<bool, boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value>());
0181 *result = negate_integer(*result, std::integral_constant<bool, boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value>());
0182 }
0183 }
0184
0185 template <class R, std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0186 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_floating_point<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
0187 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) noexcept(boost::multiprecision::detail::is_arithmetic<R>::value &&
0188 (std::numeric_limits<R>::has_infinity ||
0189 std::numeric_limits<R>::has_quiet_NaN))
0190 {
0191 BOOST_MP_FLOAT128_USING using std::ldexp;
0192 if (eval_is_zero(backend))
0193 {
0194 *result = 0.0f;
0195 return;
0196 }
0197
0198 #ifdef BOOST_HAS_FLOAT128
0199 std::ptrdiff_t bits_to_keep = static_cast<std::ptrdiff_t>(std::is_same<R, float128_type>::value ? 113 : std::numeric_limits<R>::digits);
0200 #else
0201 std::ptrdiff_t bits_to_keep = static_cast<std::ptrdiff_t>(std::numeric_limits<R>::digits);
0202 #endif
0203 std::ptrdiff_t bits = static_cast<std::ptrdiff_t>(eval_msb_imp(backend) + 1);
0204
0205 if (bits > bits_to_keep)
0206 {
0207
0208 *result = 0.0f;
0209 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
0210 limb_type mask = ~static_cast<limb_type>(0u);
0211 std::size_t index = backend.size() - 1;
0212 std::size_t shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits * index;
0213 while (bits_to_keep > 0)
0214 {
0215 if (bits_to_keep < (std::ptrdiff_t)cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
0216 {
0217 if(index != backend.size() - 1)
0218 {
0219 const std::ptrdiff_t left_shift_amount = static_cast<std::ptrdiff_t>(static_cast<std::ptrdiff_t>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits) - bits_to_keep);
0220
0221 mask <<= left_shift_amount;
0222 }
0223 else
0224 {
0225 std::ptrdiff_t bits_in_first_limb = static_cast<std::ptrdiff_t>(bits % static_cast<std::ptrdiff_t>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits));
0226 if (bits_in_first_limb == 0)
0227 bits_in_first_limb = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0228 if (bits_in_first_limb > bits_to_keep)
0229 mask <<= bits_in_first_limb - bits_to_keep;
0230 }
0231 }
0232 *result += ldexp(static_cast<R>(p[index] & mask), static_cast<int>(shift));
0233 shift -= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0234
0235 const bool bits_has_non_zero_remainder = (bits % static_cast<std::ptrdiff_t>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits) != 0);
0236
0237 bits_to_keep -= ((index == backend.size() - 1) && bits_has_non_zero_remainder)
0238 ? bits % static_cast<std::ptrdiff_t>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
0239 : static_cast<std::ptrdiff_t>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
0240 --index;
0241 }
0242
0243 bits -= 1 + std::numeric_limits<R>::digits;
0244 if (eval_bit_test(backend, static_cast<unsigned>(bits)))
0245 {
0246 if ((eval_lsb_imp(backend) < static_cast<std::size_t>(bits)) || eval_bit_test(backend, static_cast<std::size_t>(bits + 1)))
0247 {
0248 #ifdef BOOST_MP_MATH_AVAILABLE
0249 BOOST_IF_CONSTEXPR(std::numeric_limits<R>::has_infinity || std::numeric_limits<R>::has_quiet_NaN)
0250 {
0251
0252 *result = boost::math::float_next(*result, boost::math::policies::make_policy(boost::math::policies::overflow_error<boost::math::policies::ignore_error>(),
0253 boost::math::policies::domain_error<boost::math::policies::ignore_error>()));
0254 }
0255 else
0256 {
0257 *result = boost::math::float_next(*result);
0258 }
0259 #else
0260 using std::nextafter; BOOST_MP_FLOAT128_USING
0261 *result = nextafter(*result, *result * 2);
0262 #endif
0263 }
0264 }
0265 }
0266 else
0267 {
0268 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
0269 std::size_t shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0270 *result = static_cast<R>(*p);
0271 for (std::size_t i = 1; i < backend.size(); ++i)
0272 {
0273 *result += static_cast<R>(ldexp(static_cast<long double>(p[i]), static_cast<int>(shift)));
0274 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0275 }
0276 }
0277 if (backend.sign())
0278 *result = -*result;
0279 }
0280
0281 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0282 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
0283 eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) noexcept
0284 {
0285 return (val.size() == 1) && (val.limbs()[0] == 0);
0286 }
0287 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0288 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
0289 eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) noexcept
0290 {
0291 return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
0292 }
0293 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0294 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0295 eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0296 {
0297 result = val;
0298 result.sign(false);
0299 }
0300
0301
0302
0303
0304 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0305 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
0306 eval_lsb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
0307 {
0308
0309
0310
0311 std::size_t index = 0;
0312 while (!a.limbs()[index] && (index < a.size()))
0313 ++index;
0314
0315
0316
0317 std::size_t result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
0318
0319 return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0320 }
0321
0322 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0323 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
0324 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
0325 {
0326 using default_ops::eval_get_sign;
0327 if (eval_get_sign(a) == 0)
0328 {
0329 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
0330 }
0331 if (a.sign())
0332 {
0333 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
0334 }
0335 return eval_lsb_imp(a);
0336 }
0337
0338
0339
0340
0341 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0342 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
0343 eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
0344 {
0345
0346
0347
0348 return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
0349 }
0350
0351 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0352 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
0353 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
0354 {
0355 using default_ops::eval_get_sign;
0356 if (eval_get_sign(a) == 0)
0357 {
0358 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
0359 }
0360 if (a.sign())
0361 {
0362 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
0363 }
0364 return eval_msb_imp(a);
0365 }
0366
0367 #ifdef BOOST_GCC
0368
0369
0370
0371
0372 #pragma GCC diagnostic push
0373 #pragma GCC diagnostic ignored "-Warray-bounds"
0374 #endif
0375
0376 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0377 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
0378 eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, std::size_t index) noexcept
0379 {
0380 std::size_t offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0381 std::size_t shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0382 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
0383 if (offset >= val.size())
0384 return false;
0385 return val.limbs()[offset] & mask ? true : false;
0386 }
0387
0388 #ifdef BOOST_GCC
0389 #pragma GCC diagnostic pop
0390 #endif
0391
0392 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0393 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0394 eval_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, std::size_t index)
0395 {
0396 std::size_t offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0397 std::size_t shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0398 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
0399 if (offset >= val.size())
0400 {
0401 std::size_t os = val.size();
0402 val.resize(offset + 1, offset + 1);
0403 if (offset >= val.size())
0404 return;
0405 for (std::size_t i = os; i <= offset; ++i)
0406 val.limbs()[i] = 0;
0407 }
0408 val.limbs()[offset] |= mask;
0409 }
0410
0411 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0412 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0413 eval_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, std::size_t index) noexcept
0414 {
0415 std::size_t offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0416 std::size_t shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0417 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
0418 if (offset >= val.size())
0419 return;
0420 val.limbs()[offset] &= ~mask;
0421 val.normalize();
0422 }
0423
0424 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0425 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0426 eval_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, std::size_t index)
0427 {
0428 std::size_t offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0429 std::size_t shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0430 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
0431 if (offset >= val.size())
0432 {
0433 std::size_t os = val.size();
0434 val.resize(offset + 1, offset + 1);
0435 if (offset >= val.size())
0436 return;
0437 for (std::size_t i = os; i <= offset; ++i)
0438 val.limbs()[i] = 0;
0439 }
0440 val.limbs()[offset] ^= mask;
0441 val.normalize();
0442 }
0443
0444 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0445 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0446 eval_qr(
0447 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
0448 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
0449 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
0450 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0451 {
0452 divide_unsigned_helper(&q, x, y, r);
0453 q.sign(x.sign() != y.sign());
0454 r.sign(x.sign());
0455 }
0456
0457 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0458 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0459 eval_qr(
0460 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
0461 limb_type y,
0462 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
0463 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0464 {
0465 divide_unsigned_helper(&q, x, y, r);
0466 q.sign(x.sign());
0467 r.sign(x.sign());
0468 }
0469
0470 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
0471 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<U>::value>::type eval_qr(
0472 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
0473 U y,
0474 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
0475 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0476 {
0477 using default_ops::eval_qr;
0478 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
0479 t = y;
0480 eval_qr(x, t, q, r);
0481 }
0482
0483 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
0484 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
0485 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, Integer mod)
0486 {
0487 BOOST_IF_CONSTEXPR (sizeof(Integer) <= sizeof(limb_type))
0488 {
0489 if (mod <= (std::numeric_limits<limb_type>::max)())
0490 {
0491 const std::ptrdiff_t n = a.size();
0492 const double_limb_type two_n_mod = static_cast<limb_type>(1u) + (~static_cast<limb_type>(0u) - mod) % mod;
0493 limb_type res = a.limbs()[n - 1] % mod;
0494
0495 for (std::ptrdiff_t i = n - 2; i >= 0; --i)
0496 res = static_cast<limb_type>((res * two_n_mod + a.limbs()[i]) % mod);
0497 return res;
0498 }
0499 else
0500 return default_ops::eval_integer_modulus(a, mod);
0501 }
0502 else
0503 {
0504 return default_ops::eval_integer_modulus(a, mod);
0505 }
0506 }
0507
0508 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
0509 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
0510 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
0511 {
0512 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
0513 }
0514
0515 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR limb_type eval_gcd(limb_type u, limb_type v)
0516 {
0517
0518 if (!u || !v)
0519 return u | v;
0520 #if (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L))
0521 return std::gcd(u, v);
0522 #else
0523 std::size_t shift = boost::multiprecision::detail::find_lsb(u | v);
0524 u >>= boost::multiprecision::detail::find_lsb(u);
0525 do
0526 {
0527 v >>= boost::multiprecision::detail::find_lsb(v);
0528 if (u > v)
0529 std_constexpr::swap(u, v);
0530 v -= u;
0531 } while (v);
0532 return u << shift;
0533 #endif
0534 }
0535
0536 inline BOOST_MP_CXX14_CONSTEXPR double_limb_type eval_gcd(double_limb_type u, double_limb_type v)
0537 {
0538 #if (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L)) && (!defined(BOOST_HAS_INT128) || !defined(__STRICT_ANSI__))
0539 return std::gcd(u, v);
0540 #else
0541 if (u == 0)
0542 return v;
0543
0544 std::size_t shift = boost::multiprecision::detail::find_lsb(u | v);
0545 u >>= boost::multiprecision::detail::find_lsb(u);
0546 do
0547 {
0548 v >>= boost::multiprecision::detail::find_lsb(v);
0549 if (u > v)
0550 std_constexpr::swap(u, v);
0551 v -= u;
0552 } while (v);
0553 return u << shift;
0554 #endif
0555 }
0556
0557 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0558 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0559 eval_gcd(
0560 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0561 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0562 limb_type b)
0563 {
0564 int s = eval_get_sign(a);
0565 if (!b || !s)
0566 {
0567 result = a;
0568 *result.limbs() |= b;
0569 }
0570 else
0571 {
0572 eval_modulus(result, a, b);
0573 limb_type& res = *result.limbs();
0574 res = eval_gcd(res, b);
0575 }
0576 result.sign(false);
0577 }
0578
0579 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0580 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0581 eval_gcd(
0582 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0583 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0584 double_limb_type b)
0585 {
0586 int s = eval_get_sign(a);
0587 if (!b || !s)
0588 {
0589 if (!s)
0590 result = b;
0591 else
0592 result = a;
0593 return;
0594 }
0595 double_limb_type res = 0;
0596 if(a.sign() == 0)
0597 res = eval_integer_modulus(a, b);
0598 else
0599 {
0600 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
0601 t.negate();
0602 res = eval_integer_modulus(t, b);
0603 }
0604 res = eval_gcd(res, b);
0605 result = res;
0606 result.sign(false);
0607 }
0608 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0609 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0610 eval_gcd(
0611 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0612 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0613 signed_double_limb_type v)
0614 {
0615 eval_gcd(result, a, static_cast<double_limb_type>(v < 0 ? -v : v));
0616 }
0617
0618
0619
0620 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
0621 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0622 eval_gcd(
0623 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0624 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0625 const Integer& v)
0626 {
0627 eval_gcd(result, a, static_cast<limb_type>(v));
0628 }
0629 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
0630 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0631 eval_gcd(
0632 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0633 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0634 const Integer& v)
0635 {
0636 eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
0637 }
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667 #ifndef BOOST_HAS_INT128
0668
0669
0670
0671
0672 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Storage>
0673 void eval_gcd_lehmer(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& U, cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& V, std::size_t lu, Storage& storage)
0674 {
0675
0676
0677
0678 std::size_t h = lu % bits_per_limb;
0679 double_limb_type u = (static_cast<double_limb_type>((U.limbs()[U.size() - 1])) << bits_per_limb) | U.limbs()[U.size() - 2];
0680 double_limb_type v = (static_cast<double_limb_type>((V.size() < U.size() ? 0 : V.limbs()[V.size() - 1])) << bits_per_limb) | V.limbs()[U.size() - 2];
0681 if (h)
0682 {
0683 u <<= bits_per_limb - h;
0684 u |= U.limbs()[U.size() - 3] >> h;
0685 v <<= bits_per_limb - h;
0686 v |= V.limbs()[U.size() - 3] >> h;
0687 }
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698 double_limb_type x[3] = {1, 0};
0699 double_limb_type y[3] = {0, 1};
0700 std::size_t i = 0;
0701
0702 #ifdef BOOST_MP_GCD_DEBUG
0703 cpp_int UU, VV;
0704 UU = U;
0705 VV = V;
0706 #endif
0707
0708 while (true)
0709 {
0710 double_limb_type q = u / v;
0711 x[2] = x[0] + q * x[1];
0712 y[2] = y[0] + q * y[1];
0713 double_limb_type tu = u;
0714 u = v;
0715 v = tu - q * v;
0716 ++i;
0717
0718
0719
0720
0721
0722
0723 if (y[2] >> bits_per_limb)
0724 break;
0725
0726
0727
0728 if ((i & 1u) == 0)
0729 {
0730 BOOST_MP_ASSERT(u > v);
0731 if ((v < x[2]) || ((u - v) < (y[2] + y[1])))
0732 break;
0733 }
0734 else
0735 {
0736 BOOST_MP_ASSERT(u > v);
0737 if ((v < y[2]) || ((u - v) < (x[2] + x[1])))
0738 break;
0739 }
0740 #ifdef BOOST_MP_GCD_DEBUG
0741 BOOST_MP_ASSERT(q == UU / VV);
0742 UU %= VV;
0743 UU.swap(VV);
0744 #endif
0745 x[0] = x[1];
0746 x[1] = x[2];
0747 y[0] = y[1];
0748 y[1] = y[2];
0749 }
0750 if (i == 1)
0751 {
0752
0753 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
0754 eval_modulus(t, U, V);
0755 U.swap(V);
0756 V.swap(t);
0757 return;
0758 }
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770
0771 std::size_t ts = U.size() + 1;
0772 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t1(storage, ts), t2(storage, ts), t3(storage, ts);
0773 eval_multiply(t1, U, static_cast<limb_type>(x[0]));
0774 eval_multiply(t2, V, static_cast<limb_type>(y[0]));
0775 eval_multiply(t3, U, static_cast<limb_type>(x[1]));
0776 if ((i & 1u) == 0)
0777 {
0778 if (x[0] == 0)
0779 U = t2;
0780 else
0781 {
0782 BOOST_MP_ASSERT(t2.compare(t1) >= 0);
0783 eval_subtract(U, t2, t1);
0784 BOOST_MP_ASSERT(U.sign() == false);
0785 }
0786 }
0787 else
0788 {
0789 BOOST_MP_ASSERT(t1.compare(t2) >= 0);
0790 eval_subtract(U, t1, t2);
0791 BOOST_MP_ASSERT(U.sign() == false);
0792 }
0793 eval_multiply(t2, V, static_cast<limb_type>(y[1]));
0794 if (i & 1u)
0795 {
0796 if (x[1] == 0)
0797 V = t2;
0798 else
0799 {
0800 BOOST_MP_ASSERT(t2.compare(t3) >= 0);
0801 eval_subtract(V, t2, t3);
0802 BOOST_MP_ASSERT(V.sign() == false);
0803 }
0804 }
0805 else
0806 {
0807 BOOST_MP_ASSERT(t3.compare(t2) >= 0);
0808 eval_subtract(V, t3, t2);
0809 BOOST_MP_ASSERT(V.sign() == false);
0810 }
0811 BOOST_MP_ASSERT(U.compare(V) >= 0);
0812 BOOST_MP_ASSERT(lu > eval_msb(U));
0813 #ifdef BOOST_MP_GCD_DEBUG
0814
0815 BOOST_MP_ASSERT(UU == U);
0816 BOOST_MP_ASSERT(VV == V);
0817
0818 extern std::size_t total_lehmer_gcd_calls;
0819 extern std::size_t total_lehmer_gcd_bits_saved;
0820 extern std::size_t total_lehmer_gcd_cycles;
0821
0822 ++total_lehmer_gcd_calls;
0823 total_lehmer_gcd_bits_saved += lu - eval_msb(U);
0824 total_lehmer_gcd_cycles += i;
0825 #endif
0826 if (lu < 2048)
0827 {
0828
0829
0830
0831
0832
0833
0834
0835
0836 if ((U.limbs()[0] & 1u) == 0)
0837 {
0838 eval_right_shift(U, eval_lsb(U));
0839 if (U.compare(V) < 0)
0840 U.swap(V);
0841 }
0842 else if ((V.limbs()[0] & 1u) == 0)
0843 {
0844 eval_right_shift(V, eval_lsb(V));
0845 }
0846 }
0847 storage.deallocate(ts * 3);
0848 }
0849
0850 #else
0851
0852
0853
0854
0855
0856
0857
0858
0859
0860 BOOST_FORCEINLINE void divide_subtract(double_limb_type& q, double_limb_type& u, const double_limb_type& v)
0861 {
0862 BOOST_MP_ASSERT(q == 1);
0863 u -= v;
0864 while (u >= v)
0865 {
0866 u -= v;
0867 if (++q > 30)
0868 {
0869 double_limb_type t = u / v;
0870 u -= t * v;
0871 q += t;
0872 }
0873 }
0874 }
0875
0876 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Storage>
0877 void eval_gcd_lehmer(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& U, cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& V, std::size_t lu, Storage& storage)
0878 {
0879
0880
0881
0882 std::size_t h = lu % bits_per_limb;
0883 double_limb_type u, v;
0884 if (h)
0885 {
0886 u = (static_cast<double_limb_type>((U.limbs()[U.size() - 1])) << bits_per_limb) | U.limbs()[U.size() - 2];
0887 v = (static_cast<double_limb_type>((V.size() < U.size() ? 0 : V.limbs()[V.size() - 1])) << bits_per_limb) | V.limbs()[U.size() - 2];
0888 u <<= bits_per_limb - h;
0889 u |= U.limbs()[U.size() - 3] >> h;
0890 v <<= bits_per_limb - h;
0891 v |= V.limbs()[U.size() - 3] >> h;
0892 }
0893 else
0894 {
0895 u = (static_cast<double_limb_type>(U.limbs()[U.size() - 1]) << bits_per_limb) | U.limbs()[U.size() - 2];
0896 v = (static_cast<double_limb_type>(V.limbs()[U.size() - 1]) << bits_per_limb) | V.limbs()[U.size() - 2];
0897 }
0898
0899
0900
0901
0902
0903
0904
0905
0906 limb_type x[3] = { 1, 0 };
0907 limb_type y[3] = { 0, 1 };
0908 std::size_t i = 0;
0909
0910 #ifdef BOOST_MP_GCD_DEBUG
0911 cpp_int UU, VV;
0912 UU = U;
0913 VV = V;
0914 #endif
0915
0916
0917
0918
0919
0920
0921
0922
0923 double_limb_type old_u, old_v;
0924 while (true)
0925 {
0926 limb_type q = static_cast<limb_type>(u >> bits_per_limb) / static_cast<limb_type>(v >> bits_per_limb);
0927 x[2] = x[0] + q * x[1];
0928 y[2] = y[0] + q * y[1];
0929 double_limb_type tu = u;
0930 old_u = u;
0931 old_v = v;
0932 u = v;
0933 double_limb_type t = q * v;
0934 if (tu < t)
0935 {
0936 ++i;
0937 break;
0938 }
0939 v = tu - t;
0940 ++i;
0941 BOOST_MP_ASSERT((u <= v) || (t / q == old_v));
0942 if (u <= v)
0943 {
0944
0945 break;
0946 }
0947 if ((i & 1u) == 0)
0948 {
0949 if ((static_cast<limb_type>(v >> bits_per_limb) < x[2]) || ((static_cast<limb_type>(u >> bits_per_limb) - static_cast<limb_type>(v >> bits_per_limb)) < (y[2] + y[1])))
0950 break;
0951 }
0952 else
0953 {
0954 if ((static_cast<limb_type>(v >> bits_per_limb) < y[2]) || ((static_cast<limb_type>(u >> bits_per_limb) - static_cast<limb_type>(v >> bits_per_limb)) < (x[2] + x[1])))
0955 break;
0956 }
0957 #ifdef BOOST_MP_GCD_DEBUG
0958 BOOST_MP_ASSERT(q == UU / VV);
0959 UU %= VV;
0960 UU.swap(VV);
0961 #endif
0962 x[0] = x[1];
0963 x[1] = x[2];
0964 y[0] = y[1];
0965 y[1] = y[2];
0966 }
0967
0968
0969
0970 --i;
0971 u = old_u;
0972 v = old_v;
0973
0974
0975
0976 while (true)
0977 {
0978 double_limb_type q = 1u;
0979 double_limb_type tt = u;
0980 divide_subtract(q, u, v);
0981 std::swap(u, v);
0982 tt = y[0] + q * static_cast<double_limb_type>(y[1]);
0983
0984
0985
0986
0987 if (tt >> bits_per_limb)
0988 {
0989 ++i;
0990 break;
0991 }
0992 x[2] = static_cast<limb_type>(x[0] + static_cast<double_limb_type>(q * x[1]));
0993 y[2] = static_cast<limb_type>(tt);
0994 ++i;
0995 if ((i & 1u) == 0)
0996 {
0997 BOOST_MP_ASSERT(u > v);
0998 if ((v < x[2]) || ((u - v) < (static_cast<double_limb_type>(y[2]) + y[1])))
0999 break;
1000 }
1001 else
1002 {
1003 BOOST_MP_ASSERT(u > v);
1004 if ((v < y[2]) || ((u - v) < (static_cast<double_limb_type>(x[2]) + x[1])))
1005 break;
1006 }
1007 #ifdef BOOST_MP_GCD_DEBUG
1008 BOOST_MP_ASSERT(q == UU / VV);
1009 UU %= VV;
1010 UU.swap(VV);
1011 #endif
1012 x[0] = x[1];
1013 x[1] = x[2];
1014 y[0] = y[1];
1015 y[1] = y[2];
1016 }
1017 if (i == 1)
1018 {
1019
1020 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
1021 eval_modulus(t, U, V);
1022 U.swap(V);
1023 V.swap(t);
1024 return;
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038 std::size_t ts = U.size() + 1;
1039 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t1(storage, ts), t2(storage, ts), t3(storage, ts);
1040 eval_multiply(t1, U, x[0]);
1041 eval_multiply(t2, V, y[0]);
1042 eval_multiply(t3, U, x[1]);
1043 if ((i & 1u) == 0)
1044 {
1045 if (x[0] == 0)
1046 U = t2;
1047 else
1048 {
1049 BOOST_MP_ASSERT(t2.compare(t1) >= 0);
1050 eval_subtract(U, t2, t1);
1051 BOOST_MP_ASSERT(U.sign() == false);
1052 }
1053 }
1054 else
1055 {
1056 BOOST_MP_ASSERT(t1.compare(t2) >= 0);
1057 eval_subtract(U, t1, t2);
1058 BOOST_MP_ASSERT(U.sign() == false);
1059 }
1060 eval_multiply(t2, V, y[1]);
1061 if (i & 1u)
1062 {
1063 if (x[1] == 0)
1064 V = t2;
1065 else
1066 {
1067 BOOST_MP_ASSERT(t2.compare(t3) >= 0);
1068 eval_subtract(V, t2, t3);
1069 BOOST_MP_ASSERT(V.sign() == false);
1070 }
1071 }
1072 else
1073 {
1074 BOOST_MP_ASSERT(t3.compare(t2) >= 0);
1075 eval_subtract(V, t3, t2);
1076 BOOST_MP_ASSERT(V.sign() == false);
1077 }
1078 BOOST_MP_ASSERT(U.compare(V) >= 0);
1079 BOOST_MP_ASSERT(lu > eval_msb(U));
1080 #ifdef BOOST_MP_GCD_DEBUG
1081
1082 BOOST_MP_ASSERT(UU == U);
1083 BOOST_MP_ASSERT(VV == V);
1084
1085 extern std::size_t total_lehmer_gcd_calls;
1086 extern std::size_t total_lehmer_gcd_bits_saved;
1087 extern std::size_t total_lehmer_gcd_cycles;
1088
1089 ++total_lehmer_gcd_calls;
1090 total_lehmer_gcd_bits_saved += lu - eval_msb(U);
1091 total_lehmer_gcd_cycles += i;
1092 #endif
1093 if (lu < 2048)
1094 {
1095
1096
1097
1098
1099
1100
1101
1102
1103 if ((U.limbs()[0] & 1u) == 0)
1104 {
1105 eval_right_shift(U, eval_lsb(U));
1106 if (U.compare(V) < 0)
1107 U.swap(V);
1108 }
1109 else if ((V.limbs()[0] & 1u) == 0)
1110 {
1111 eval_right_shift(V, eval_lsb(V));
1112 }
1113 }
1114 storage.deallocate(ts * 3);
1115 }
1116
1117 #endif
1118
1119 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1120 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
1121 eval_gcd(
1122 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
1123 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
1124 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b)
1125 {
1126 using default_ops::eval_get_sign;
1127 using default_ops::eval_is_zero;
1128 using default_ops::eval_lsb;
1129
1130 if (a.size() == 1)
1131 {
1132 eval_gcd(result, b, *a.limbs());
1133 return;
1134 }
1135 if (b.size() == 1)
1136 {
1137 eval_gcd(result, a, *b.limbs());
1138 return;
1139 }
1140 std::size_t temp_size = (std::max)(a.size(), b.size()) + 1;
1141 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::scoped_shared_storage storage(a, temp_size * 6);
1142
1143 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> U(storage, temp_size);
1144 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> V(storage, temp_size);
1145 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(storage, temp_size);
1146 U = a;
1147 V = b;
1148
1149 int s = eval_get_sign(U);
1150
1151
1152 if (s < 0)
1153 {
1154 U.negate();
1155 }
1156 else if (s == 0)
1157 {
1158 result = V;
1159 return;
1160 }
1161 s = eval_get_sign(V);
1162 if (s < 0)
1163 {
1164 V.negate();
1165 }
1166 else if (s == 0)
1167 {
1168 result = U;
1169 return;
1170 }
1171
1172
1173
1174 std::size_t us = eval_lsb(U);
1175 std::size_t vs = eval_lsb(V);
1176 std::size_t shift = (std::min)(us, vs);
1177 if (us)
1178 eval_right_shift(U, us);
1179 if (vs)
1180 eval_right_shift(V, vs);
1181
1182 if (U.compare(V) < 0)
1183 U.swap(V);
1184
1185 while (!eval_is_zero(V))
1186 {
1187 if (U.size() <= 2)
1188 {
1189
1190
1191
1192
1193
1194 if (U.size() == 1)
1195 U = eval_gcd(*V.limbs(), *U.limbs());
1196 else
1197 {
1198 double_limb_type i = U.limbs()[0] | (static_cast<double_limb_type>(U.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
1199 double_limb_type j = (V.size() == 1) ? *V.limbs() : V.limbs()[0] | (static_cast<double_limb_type>(V.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
1200 U = eval_gcd(i, j);
1201 }
1202 break;
1203 }
1204 std::size_t lu = eval_msb(U) + 1;
1205 std::size_t lv = eval_msb(V) + 1;
1206 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
1207 if (!BOOST_MP_IS_CONST_EVALUATED(lu) && (lu - lv <= bits_per_limb / 2))
1208 #else
1209 if (lu - lv <= bits_per_limb / 2)
1210 #endif
1211 {
1212 eval_gcd_lehmer(U, V, lu, storage);
1213 }
1214 else
1215 {
1216 eval_modulus(t, U, V);
1217 U.swap(V);
1218 V.swap(t);
1219 }
1220 }
1221 result = U;
1222 if (shift)
1223 eval_left_shift(result, shift);
1224 }
1225
1226
1227
1228 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1229 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
1230 eval_gcd(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) noexcept
1231 {
1232 *result.limbs() = boost::multiprecision::detail::constexpr_gcd(*a.limbs(), *b.limbs());
1233 result.sign(false);
1234 }
1235
1236 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1237 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
1238 eval_lcm(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
1239 {
1240 *result.limbs() = boost::multiprecision::detail::constexpr_lcm(*a.limbs(), *b.limbs());
1241 result.normalize();
1242 result.sign(false);
1243 }
1244
1245 inline void conversion_overflow(const std::integral_constant<int, checked>&)
1246 {
1247 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
1248 }
1249 inline BOOST_MP_CXX14_CONSTEXPR void conversion_overflow(const std::integral_constant<int, unchecked>&) {}
1250
1251 #if defined(__clang__) && defined(__MINGW32__)
1252
1253
1254
1255
1256
1257 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1258 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
1259 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_same<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, double_limb_type>::value>::type
1260 eval_convert_to(float* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
1261 {
1262 float f = static_cast<std::uint64_t>((*val.limbs()) >> 64);
1263 *result = std::ldexp(f, 64);
1264 *result += static_cast<std::uint64_t>((*val.limbs()));
1265 if(val.sign())
1266 *result = -*result;
1267 }
1268 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1269 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
1270 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_same<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, double_limb_type>::value>::type
1271 eval_convert_to(double* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
1272 {
1273 float f = static_cast<std::uint64_t>((*val.limbs()) >> 64);
1274 *result = std::ldexp(f, 64);
1275 *result += static_cast<std::uint64_t>((*val.limbs()));
1276 if(val.sign())
1277 *result = -*result;
1278 }
1279 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1280 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
1281 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_same<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, double_limb_type>::value>::type
1282 eval_convert_to(long double* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
1283 {
1284 float f = static_cast<std::uint64_t>((*val.limbs()) >> 64);
1285 *result = std::ldexp(f, 64);
1286 *result += static_cast<std::uint64_t>((*val.limbs()));
1287 if(val.sign())
1288 *result = -*result;
1289 }
1290 #endif
1291
1292 template <class R, std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1293 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
1294 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value>::type
1295 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
1296 {
1297 BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_specialized)
1298 {
1299 using common_type = typename std::common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type;
1300
1301 if (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)()))
1302 {
1303 if (val.isneg())
1304 {
1305 check_is_negative(std::integral_constant < bool, (boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value) || (number_category<R>::value == number_kind_floating_point) > ());
1306 if (static_cast<common_type>(*val.limbs()) > -static_cast<common_type>((std::numeric_limits<R>::min)()))
1307 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
1308 *result = (std::numeric_limits<R>::min)();
1309 }
1310 else
1311 {
1312 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
1313 *result = boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value ? (std::numeric_limits<R>::max)() : static_cast<R>(*val.limbs());
1314 }
1315 }
1316 else
1317 {
1318 *result = static_cast<R>(*val.limbs());
1319 if (val.isneg())
1320 {
1321 check_is_negative(std::integral_constant < bool, (boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value) || (number_category<R>::value == number_kind_floating_point) > ());
1322 *result = negate_integer(*result, std::integral_constant < bool, is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point) > ());
1323 }
1324 }
1325 }
1326 else
1327 {
1328 *result = static_cast<R>(*val.limbs());
1329 if (val.isneg())
1330 {
1331 check_is_negative(std::integral_constant<bool, (boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value) || (number_category<R>::value == number_kind_floating_point) > ());
1332 *result = negate_integer(*result, std::integral_constant<bool, is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point) > ());
1333 }
1334 }
1335 }
1336
1337 template <class R, std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1338 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
1339 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value>::type
1340 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
1341 {
1342 BOOST_IF_CONSTEXPR(std::numeric_limits<R>::is_specialized)
1343 {
1344 using common_type = typename std::common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type;
1345
1346 if(static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)()))
1347 {
1348 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
1349 *result = boost::multiprecision::detail::is_signed<R>::value && boost::multiprecision::detail::is_integral<R>::value ? (std::numeric_limits<R>::max)() : static_cast<R>(*val.limbs());
1350 }
1351 else
1352 *result = static_cast<R>(*val.limbs());
1353 }
1354 else
1355 *result = static_cast<R>(*val.limbs());
1356 }
1357
1358 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1359 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
1360 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
1361 {
1362 using default_ops::eval_get_sign;
1363 if (eval_get_sign(a) == 0)
1364 {
1365 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1366 }
1367 if (a.sign())
1368 {
1369 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1370 }
1371
1372
1373
1374 return boost::multiprecision::detail::find_lsb(*a.limbs());
1375 }
1376
1377 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1378 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
1379 eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
1380 {
1381
1382
1383
1384 return boost::multiprecision::detail::find_msb(*a.limbs());
1385 }
1386
1387 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1388 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, std::size_t>::type
1389 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
1390 {
1391 using default_ops::eval_get_sign;
1392 if (eval_get_sign(a) == 0)
1393 {
1394 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
1395 }
1396 if (a.sign())
1397 {
1398 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
1399 }
1400 return eval_msb_imp(a);
1401 }
1402
1403 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
1404 inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) noexcept
1405 {
1406 std::size_t result = 0;
1407 for (std::size_t i = 0; i < val.size(); ++i)
1408 {
1409 boost::multiprecision::detail::hash_combine(result, val.limbs()[i]);
1410 }
1411 boost::multiprecision::detail::hash_combine(result, val.sign());
1412 return result;
1413 }
1414
1415 #ifdef BOOST_MSVC
1416 #pragma warning(pop)
1417 #endif
1418
1419 }
1420
1421 namespace detail {
1422
1423 #ifndef BOOST_MP_STANDALONE
1424 template <typename T>
1425 inline BOOST_CXX14_CONSTEXPR T constexpr_gcd(T a, T b) noexcept
1426 {
1427 return boost::integer::gcd(a, b);
1428 }
1429
1430 template <typename T>
1431 inline BOOST_CXX14_CONSTEXPR T constexpr_lcm(T a, T b) noexcept
1432 {
1433 return boost::integer::lcm(a, b);
1434 }
1435
1436 #else
1437
1438 template <typename T>
1439 inline BOOST_CXX14_CONSTEXPR T constexpr_gcd(T a, T b) noexcept
1440 {
1441 return boost::multiprecision::backends::eval_gcd(a, b);
1442 }
1443
1444 template <typename T>
1445 inline BOOST_CXX14_CONSTEXPR T constexpr_lcm(T a, T b) noexcept
1446 {
1447 const T ab_gcd = boost::multiprecision::detail::constexpr_gcd(a, b);
1448 return (a * b) / ab_gcd;
1449 }
1450
1451 #endif
1452
1453 }
1454
1455 }}
1456
1457 #endif