File indexing completed on 2025-01-18 09:42:31
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MP_INTEGER_HPP
0008 #define BOOST_MP_INTEGER_HPP
0009
0010 #include <type_traits>
0011 #include <boost/multiprecision/cpp_int.hpp>
0012 #include <boost/multiprecision/detail/bitscan.hpp>
0013 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0014 #include <boost/multiprecision/detail/standalone_config.hpp>
0015
0016 namespace boost {
0017 namespace multiprecision {
0018
0019 template <class Integer, class I2>
0020 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value && boost::multiprecision::detail::is_integral<I2>::value, Integer&>::type
0021 multiply(Integer& result, const I2& a, const I2& b)
0022 {
0023 return result = static_cast<Integer>(a) * static_cast<Integer>(b);
0024 }
0025 template <class Integer, class I2>
0026 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value && boost::multiprecision::detail::is_integral<I2>::value, Integer&>::type
0027 add(Integer& result, const I2& a, const I2& b)
0028 {
0029 return result = static_cast<Integer>(a) + static_cast<Integer>(b);
0030 }
0031 template <class Integer, class I2>
0032 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value && boost::multiprecision::detail::is_integral<I2>::value, Integer&>::type
0033 subtract(Integer& result, const I2& a, const I2& b)
0034 {
0035 return result = static_cast<Integer>(a) - static_cast<Integer>(b);
0036 }
0037
0038 template <class Integer>
0039 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value>::type divide_qr(const Integer& x, const Integer& y, Integer& q, Integer& r)
0040 {
0041 q = x / y;
0042 r = x % y;
0043 }
0044
0045 template <class I1, class I2>
0046 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
0047 {
0048 return static_cast<I2>(x % val);
0049 }
0050
0051 namespace detail {
0052
0053
0054
0055
0056
0057
0058 template <class I>
0059 struct double_integer
0060 {
0061 static constexpr const unsigned int_t_digits =
0062 2 * sizeof(I) <= sizeof(long long) ? std::numeric_limits<I>::digits * 2 : 1;
0063
0064 using type = typename std::conditional<
0065 2 * sizeof(I) <= sizeof(long long),
0066 typename std::conditional<
0067 boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value,
0068 typename boost::multiprecision::detail::int_t<int_t_digits>::least,
0069 typename boost::multiprecision::detail::uint_t<int_t_digits>::least>::type,
0070 typename std::conditional<
0071 2 * sizeof(I) <= sizeof(double_limb_type),
0072 typename std::conditional<
0073 boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value,
0074 signed_double_limb_type,
0075 double_limb_type>::type,
0076 number<cpp_int_backend<sizeof(I) * CHAR_BIT * 2, sizeof(I) * CHAR_BIT * 2, (boost::multiprecision::detail::is_signed<I>::value ? signed_magnitude : unsigned_magnitude), unchecked, void> > >::type>::type;
0077 };
0078
0079 }
0080
0081 template <class I1, class I2, class I3>
0082 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_unsigned<I2>::value && boost::multiprecision::detail::is_integral<I3>::value, I1>::type
0083 powm(const I1& a, I2 b, I3 c)
0084 {
0085 using double_type = typename detail::double_integer<I1>::type;
0086
0087 I1 x(1), y(a);
0088 double_type result(0);
0089
0090 while (b > 0)
0091 {
0092 if (b & 1)
0093 {
0094 multiply(result, x, y);
0095 x = integer_modulus(result, c);
0096 }
0097 multiply(result, y, y);
0098 y = integer_modulus(result, c);
0099 b >>= 1;
0100 }
0101 return x % c;
0102 }
0103
0104 template <class I1, class I2, class I3>
0105 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_signed<I2>::value && boost::multiprecision::detail::is_integral<I2>::value && boost::multiprecision::detail::is_integral<I3>::value, I1>::type
0106 powm(const I1& a, I2 b, I3 c)
0107 {
0108 if (b < 0)
0109 {
0110 BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
0111 }
0112 return powm(a, static_cast<typename boost::multiprecision::detail::make_unsigned<I2>::type>(b), c);
0113 }
0114
0115 template <class Integer>
0116 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, std::size_t>::type lsb(const Integer& val)
0117 {
0118 if (val <= 0)
0119 {
0120 if (val == 0)
0121 {
0122 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
0123 }
0124 else
0125 {
0126 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
0127 }
0128 }
0129 return detail::find_lsb(val);
0130 }
0131
0132 template <class Integer>
0133 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, std::size_t>::type msb(Integer val)
0134 {
0135 if (val <= 0)
0136 {
0137 if (val == 0)
0138 {
0139 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
0140 }
0141 else
0142 {
0143 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
0144 }
0145 }
0146 return detail::find_msb(val);
0147 }
0148
0149 template <class Integer>
0150 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, bool>::type bit_test(const Integer& val, std::size_t index)
0151 {
0152 Integer mask = 1;
0153 if (index >= sizeof(Integer) * CHAR_BIT)
0154 return 0;
0155 if (index)
0156 mask <<= index;
0157 return val & mask ? true : false;
0158 }
0159
0160 template <class Integer>
0161 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, Integer&>::type bit_set(Integer& val, std::size_t index)
0162 {
0163 Integer mask = 1;
0164 if (index >= sizeof(Integer) * CHAR_BIT)
0165 return val;
0166 if (index)
0167 mask <<= index;
0168 val |= mask;
0169 return val;
0170 }
0171
0172 template <class Integer>
0173 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, Integer&>::type bit_unset(Integer& val, std::size_t index)
0174 {
0175 Integer mask = 1;
0176 if (index >= sizeof(Integer) * CHAR_BIT)
0177 return val;
0178 if (index)
0179 mask <<= index;
0180 val &= ~mask;
0181 return val;
0182 }
0183
0184 template <class Integer>
0185 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, Integer&>::type bit_flip(Integer& val, std::size_t index)
0186 {
0187 Integer mask = 1;
0188 if (index >= sizeof(Integer) * CHAR_BIT)
0189 return val;
0190 if (index)
0191 mask <<= index;
0192 val ^= mask;
0193 return val;
0194 }
0195
0196 namespace detail {
0197
0198 template <class Integer>
0199 BOOST_MP_CXX14_CONSTEXPR Integer karatsuba_sqrt(const Integer& x, Integer& r, size_t bits)
0200 {
0201
0202
0203
0204
0205
0206 #ifndef __clang__
0207 typedef typename std::conditional<(std::numeric_limits<long double>::digits == 64), long double, double>::type real_cast_type;
0208 #else
0209
0210 typedef double real_cast_type;
0211 #endif
0212
0213
0214
0215
0216
0217 constexpr std::size_t cutoff = (std::numeric_limits<real_cast_type>::digits * 4) / 3;
0218
0219
0220
0221 #ifdef BOOST_HAS_INT128
0222 using cutoff_t = typename std::conditional<(cutoff > 64), uint128_type, std::uint64_t>::type;
0223 #else
0224 using cutoff_t = std::uint64_t;
0225 #endif
0226
0227
0228
0229 if (bits <= cutoff)
0230 {
0231 constexpr cutoff_t half_bits = (cutoff_t(1u) << ((sizeof(cutoff_t) * CHAR_BIT) / 2)) - 1;
0232 cutoff_t val = static_cast<cutoff_t>(x);
0233 real_cast_type real_val = static_cast<real_cast_type>(val);
0234 cutoff_t s64 = static_cast<cutoff_t>(std::sqrt(real_val));
0235
0236
0237 while ((s64 > half_bits) || (s64 * s64 > val))
0238 s64--;
0239
0240 while ((s64 < half_bits) && ((s64 + 1) * (s64 + 1) <= val))
0241 s64++;
0242 r = static_cast<Integer>(val - s64 * s64);
0243 return static_cast<Integer>(s64);
0244 }
0245
0246 std::size_t b = bits / 4;
0247 Integer q = x;
0248 q >>= b * 2;
0249 Integer s = karatsuba_sqrt(q, r, bits - b * 2);
0250 Integer t = 0u;
0251 bit_set(t, static_cast<unsigned>(b * 2));
0252 r <<= b;
0253 t--;
0254 t &= x;
0255 t >>= b;
0256 t += r;
0257 s <<= 1;
0258 divide_qr(t, s, q, r);
0259 r <<= b;
0260 t = 0u;
0261 bit_set(t, static_cast<unsigned>(b));
0262 t--;
0263 t &= x;
0264 r += t;
0265 s <<= (b - 1);
0266 s += q;
0267 q *= q;
0268
0269 if (r < q)
0270 {
0271 t = s;
0272 t <<= 1;
0273 t--;
0274 r += t;
0275 s--;
0276 }
0277 r -= q;
0278 return s;
0279 }
0280
0281 template <class Integer>
0282 BOOST_MP_CXX14_CONSTEXPR Integer bitwise_sqrt(const Integer& x, Integer& r)
0283 {
0284
0285
0286
0287
0288
0289
0290
0291 Integer s = 0;
0292 switch (x)
0293 {
0294 case 0:
0295 r = 0;
0296 return s;
0297 case 1:
0298 r = 0;
0299 return 1;
0300 case 2:
0301 r = 1;
0302 return 1;
0303 case 3:
0304 r = 2;
0305 return 1;
0306 default:
0307 break;
0308
0309 }
0310 std::ptrdiff_t g = msb(x);
0311
0312 Integer t = 0;
0313 r = x;
0314 g /= 2;
0315 bit_set(s, g);
0316 bit_set(t, 2 * g);
0317 r = x - t;
0318 --g;
0319 do
0320 {
0321 t = s;
0322 t <<= g + 1;
0323 bit_set(t, 2 * g);
0324 if (t <= r)
0325 {
0326 bit_set(s, g);
0327 r -= t;
0328 }
0329 --g;
0330 } while (g >= 0);
0331 return s;
0332 }
0333
0334 }
0335
0336 template <class Integer>
0337 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, Integer>::type sqrt(const Integer& x, Integer& r)
0338 {
0339 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0340
0341 if (BOOST_MP_IS_CONST_EVALUATED(x))
0342 {
0343 return detail::bitwise_sqrt(x, r);
0344 }
0345 #endif
0346 if (x == 0u) {
0347 r = 0u;
0348 return 0u;
0349 }
0350
0351 return detail::karatsuba_sqrt(x, r, msb(x) + 1);
0352 }
0353
0354 template <class Integer>
0355 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<Integer>::value, Integer>::type sqrt(const Integer& x)
0356 {
0357 Integer r(0);
0358 return sqrt(x, r);
0359 }
0360
0361 }}
0362
0363 #endif