File indexing completed on 2025-01-18 09:42:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_MP_CPP_INT_MULTIPLY_HPP
0011 #define BOOST_MP_CPP_INT_MULTIPLY_HPP
0012
0013 #include <limits>
0014 #include <boost/multiprecision/detail/standalone_config.hpp>
0015 #include <boost/multiprecision/detail/endian.hpp>
0016 #include <boost/multiprecision/detail/assert.hpp>
0017 #include <boost/multiprecision/integer.hpp>
0018
0019 namespace boost { namespace multiprecision { namespace backends {
0020
0021 #ifdef BOOST_MSVC
0022 #pragma warning(push)
0023 #pragma warning(disable : 4127)
0024 #endif
0025
0026
0027
0028 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0029 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0030 eval_multiply(
0031 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0032 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0033 const limb_type& val) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0034 {
0035 if (!val)
0036 {
0037 result = static_cast<limb_type>(0);
0038 return;
0039 }
0040 if ((void*)&a != (void*)&result)
0041 result.resize(a.size(), a.size());
0042 double_limb_type carry = 0;
0043 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
0044 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
0045 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
0046 while (p != pe)
0047 {
0048 carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
0049 #ifdef __MSVC_RUNTIME_CHECKS
0050 *p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0051 #else
0052 *p = static_cast<limb_type>(carry);
0053 #endif
0054 carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0055 ++p, ++pa;
0056 }
0057 if (carry)
0058 {
0059 std::size_t i = result.size();
0060 result.resize(i + 1, i + 1);
0061 if (result.size() > i)
0062 result.limbs()[i] = static_cast<limb_type>(carry);
0063 }
0064 result.sign(a.sign());
0065 if (is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
0066 result.normalize();
0067 }
0068
0069
0070
0071
0072
0073
0074 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0075 inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& , std::size_t ) {}
0076
0077 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, class Allocator1>
0078 inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, Allocator1>& result, std::size_t required)
0079 {
0080 if (result.size() < required)
0081 result.resize(required, required);
0082 }
0083
0084
0085
0086 #ifdef BOOST_MP_KARATSUBA_CUTOFF
0087 const size_t karatsuba_cutoff = BOOST_MP_KARATSUBA_CUTOFF;
0088 #else
0089 const size_t karatsuba_cutoff = 40;
0090 #endif
0091
0092
0093
0094
0095
0096
0097 template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
0098 inline void multiply_karatsuba(
0099 cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& result,
0100 const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a,
0101 const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& b,
0102 typename cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>::scoped_shared_storage& storage)
0103 {
0104 using cpp_int_type = cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>;
0105
0106 std::size_t as = a.size();
0107 std::size_t bs = b.size();
0108
0109
0110
0111
0112 if ((as < karatsuba_cutoff) || (bs < karatsuba_cutoff))
0113 {
0114 eval_multiply(result, a, b);
0115 return;
0116 }
0117
0118
0119
0120 std::size_t n = (as > bs ? as : bs) / 2 + 1;
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135 std::size_t sz = (std::min)(as, n);
0136 const cpp_int_type a_l(a.limbs(), 0, sz);
0137
0138 sz = (std::min)(bs, n);
0139 const cpp_int_type b_l(b.limbs(), 0, sz);
0140
0141 limb_type zero = 0;
0142 const cpp_int_type a_h(as > n ? a.limbs() + n : &zero, 0, as > n ? as - n : 1);
0143 const cpp_int_type b_h(bs > n ? b.limbs() + n : &zero, 0, bs > n ? bs - n : 1);
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 cpp_int_type t1(storage, 2 * n + 2);
0155 cpp_int_type t2(storage, n + 1);
0156 cpp_int_type t3(storage, n + 1);
0157
0158
0159
0160
0161
0162
0163
0164
0165 cpp_int_type result_low(result.limbs(), 0, 2 * n);
0166 cpp_int_type result_high(result.limbs(), 2 * n, result.size() - 2 * n);
0167
0168
0169
0170 multiply_karatsuba(result_low, a_l, b_l, storage);
0171
0172
0173
0174
0175
0176
0177
0178 for (std::size_t i = result_low.size(); i < 2 * n; ++i)
0179 result.limbs()[i] = 0;
0180
0181
0182
0183 multiply_karatsuba(result_high, a_h, b_h, storage);
0184 for (std::size_t i = result_high.size() + 2 * n; i < result.size(); ++i)
0185 result.limbs()[i] = 0;
0186
0187
0188
0189 add_unsigned(t2, a_l, a_h);
0190 add_unsigned(t3, b_l, b_h);
0191 multiply_karatsuba(t1, t2, t3, storage);
0192
0193
0194
0195
0196
0197
0198
0199
0200 subtract_unsigned(t1, t1, result_high);
0201 subtract_unsigned(t1, t1, result_low);
0202
0203
0204
0205
0206
0207 cpp_int_type result_alias(result.limbs(), n, result.size() - n);
0208 add_unsigned(result_alias, result_alias, t1);
0209
0210
0211
0212 storage.deallocate(t1.capacity() + t2.capacity() + t3.capacity());
0213
0214 result.normalize();
0215 }
0216
0217 inline std::size_t karatsuba_storage_size(std::size_t s)
0218 {
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 return 5 * s;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239 template <std::size_t MinBits, std::size_t MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
0240 inline typename std::enable_if<!is_fixed_precision<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value>::type
0241 setup_karatsuba(
0242 cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result,
0243 const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& a,
0244 const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& b)
0245 {
0246 std::size_t as = a.size();
0247 std::size_t bs = b.size();
0248 std::size_t s = as > bs ? as : bs;
0249 std::size_t storage_size = karatsuba_storage_size(s);
0250 if (storage_size < 300)
0251 {
0252
0253
0254
0255
0256
0257 limb_type limbs[300];
0258 typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::scoped_shared_storage storage(limbs, storage_size);
0259 multiply_karatsuba(result, a, b, storage);
0260 }
0261 else
0262 {
0263 typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::scoped_shared_storage storage(result.allocator(), storage_size);
0264 multiply_karatsuba(result, a, b, storage);
0265 }
0266 }
0267
0268 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
0269 inline typename std::enable_if<is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_fixed_precision<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value || is_fixed_precision<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
0270 setup_karatsuba(
0271 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0272 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0273 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
0274 {
0275
0276
0277
0278
0279
0280
0281
0282
0283 using variable_precision_type = cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> >;
0284 variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
0285 std::size_t as = a.size();
0286 std::size_t bs = b.size();
0287 std::size_t s = as > bs ? as : bs;
0288 std::size_t sz = as + bs;
0289 std::size_t storage_size = karatsuba_storage_size(s);
0290
0291 if (!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || (sz * sizeof(limb_type) * CHAR_BIT <= MaxBits1))
0292 {
0293
0294 result.resize(sz, sz);
0295 variable_precision_type t(result.limbs(), 0, result.size());
0296 typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
0297 multiply_karatsuba(t, a_t, b_t, storage);
0298 result.resize(t.size(), t.size());
0299 }
0300 else
0301 {
0302
0303
0304
0305
0306 typename variable_precision_type::scoped_shared_storage storage(variable_precision_type::allocator_type(), sz + storage_size);
0307 variable_precision_type t(storage, sz);
0308 multiply_karatsuba(t, a_t, b_t, storage);
0309
0310
0311
0312 result = t;
0313 }
0314 }
0315 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
0316 inline typename std::enable_if<!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_fixed_precision<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_fixed_precision<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
0317 setup_karatsuba(
0318 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0319 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0320 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
0321 {
0322
0323
0324
0325 using variable_precision_type = cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> >;
0326 variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
0327 std::size_t as = a.size();
0328 std::size_t bs = b.size();
0329 std::size_t s = as > bs ? as : bs;
0330 std::size_t sz = as + bs;
0331 std::size_t storage_size = karatsuba_storage_size(s);
0332
0333 result.resize(sz, sz);
0334 variable_precision_type t(result.limbs(), 0, result.size());
0335 typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
0336 multiply_karatsuba(t, a_t, b_t, storage);
0337 }
0338
0339 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
0340 inline BOOST_MP_CXX14_CONSTEXPR void
0341 eval_multiply_comba(
0342 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0343 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0344 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0345 {
0346
0347
0348
0349
0350
0351 std::ptrdiff_t as = a.size(),
0352 bs = b.size(),
0353 rs = result.size();
0354 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
0355
0356 double_limb_type carry = 0,
0357 temp = 0;
0358 limb_type overflow = 0;
0359 const std::size_t limb_bits = sizeof(limb_type) * CHAR_BIT;
0360 const bool must_throw = rs < as + bs - 1;
0361 for (std::ptrdiff_t r = 0, lim = (std::min)(rs, as + bs - 1); r < lim; ++r, overflow = 0)
0362 {
0363 std::ptrdiff_t i = r >= as ? as - 1 : r,
0364 j = r - i,
0365 k = i < bs - j ? i + 1 : bs - j;
0366
0367 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs() + i;
0368 typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs() + j;
0369
0370 temp = carry;
0371 carry += static_cast<double_limb_type>(*(pa)) * (*(pb));
0372 overflow += carry < temp;
0373 for (--k; k; k--)
0374 {
0375 temp = carry;
0376 carry += static_cast<double_limb_type>(*(--pa)) * (*(++pb));
0377 overflow += carry < temp;
0378 }
0379 *(pr++) = static_cast<limb_type>(carry);
0380 carry = (static_cast<double_limb_type>(overflow) << limb_bits) | (carry >> limb_bits);
0381 }
0382 if (carry || must_throw)
0383 {
0384 resize_for_carry(result, as + bs);
0385 if (static_cast<int>(result.size()) >= as + bs)
0386 *pr = static_cast<limb_type>(carry);
0387 }
0388 }
0389 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
0390 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
0391 eval_multiply(
0392 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0393 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0394 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
0395 noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
0396 && (karatsuba_cutoff * sizeof(limb_type) * CHAR_BIT > MaxBits1)
0397 && (karatsuba_cutoff * sizeof(limb_type)* CHAR_BIT > MaxBits2)
0398 && (karatsuba_cutoff * sizeof(limb_type)* CHAR_BIT > MaxBits3)))
0399 {
0400
0401
0402
0403
0404
0405 std::size_t as = a.size();
0406 std::size_t bs = b.size();
0407 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
0408 typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
0409 if (as == 1)
0410 {
0411 bool s = b.sign() != a.sign();
0412 if (bs == 1)
0413 {
0414 result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
0415 }
0416 else
0417 {
0418 limb_type l = *pa;
0419 eval_multiply(result, b, l);
0420 }
0421 result.sign(s);
0422 return;
0423 }
0424 if (bs == 1)
0425 {
0426 bool s = b.sign() != a.sign();
0427 limb_type l = *pb;
0428 eval_multiply(result, a, l);
0429 result.sign(s);
0430 return;
0431 }
0432
0433 if ((void*)&result == (void*)&a)
0434 {
0435 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
0436 eval_multiply(result, t, b);
0437 return;
0438 }
0439 if ((void*)&result == (void*)&b)
0440 {
0441 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
0442 eval_multiply(result, a, t);
0443 return;
0444 }
0445
0446 constexpr double_limb_type limb_max = static_cast<double_limb_type>(~static_cast<limb_type>(0u));
0447 constexpr double_limb_type double_limb_max = static_cast<double_limb_type>(~static_cast<double_limb_type>(0u));
0448
0449 result.resize(as + bs, as + bs - 1);
0450 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0451 if (!BOOST_MP_IS_CONST_EVALUATED(as) && (as >= karatsuba_cutoff && bs >= karatsuba_cutoff))
0452 #else
0453 if (as >= karatsuba_cutoff && bs >= karatsuba_cutoff)
0454 #endif
0455 {
0456 setup_karatsuba(result, a, b);
0457
0458
0459
0460 result.sign(a.sign() != b.sign());
0461 return;
0462 }
0463 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
0464 static_assert(double_limb_max - 2 * limb_max >= limb_max * limb_max, "failed limb size sanity check");
0465
0466 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0467 if (BOOST_MP_IS_CONST_EVALUATED(as))
0468 {
0469 for (std::size_t i = 0; i < result.size(); ++i)
0470 pr[i] = 0;
0471 }
0472 else
0473 #endif
0474 std::memset(pr, 0, result.size() * sizeof(limb_type));
0475
0476 #if defined(BOOST_MP_COMBA)
0477
0478
0479
0480
0481
0482 eval_multiply_comba(result, a, b);
0483 #else
0484
0485 double_limb_type carry = 0;
0486 for (std::size_t i = 0; i < as; ++i)
0487 {
0488 BOOST_MP_ASSERT(result.size() > i);
0489 std::size_t inner_limit = !is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value ? bs : (std::min)(result.size() - i, bs);
0490 std::size_t j = 0;
0491 for (; j < inner_limit; ++j)
0492 {
0493 BOOST_MP_ASSERT(i + j < result.size());
0494 #if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
0495 BOOST_MP_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >
0496 static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value) * static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value)));
0497 #endif
0498 carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
0499 BOOST_MP_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i + j]));
0500 carry += pr[i + j];
0501 #ifdef __MSVC_RUNTIME_CHECKS
0502 pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0503 #else
0504 pr[i + j] = static_cast<limb_type>(carry);
0505 #endif
0506 carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
0507 BOOST_MP_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
0508 }
0509 if (carry)
0510 {
0511 resize_for_carry(result, i + j + 1);
0512 if (i + j < result.size())
0513 #ifdef __MSVC_RUNTIME_CHECKS
0514 pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0515 #else
0516 pr[i + j] = static_cast<limb_type>(carry);
0517 #endif
0518 }
0519 carry = 0;
0520 }
0521 #endif
0522
0523 result.normalize();
0524
0525
0526
0527 result.sign(a.sign() != b.sign());
0528 }
0529
0530 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0531 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0532 eval_multiply(
0533 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0534 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a)
0535 noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>()))))
0536 {
0537 eval_multiply(result, result, a);
0538 }
0539
0540 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0541 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
0542 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& val)
0543 noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const limb_type&>()))))
0544 {
0545 eval_multiply(result, result, val);
0546 }
0547
0548 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0549 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0550 eval_multiply(
0551 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0552 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0553 const double_limb_type& val)
0554 noexcept(
0555 (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const limb_type&>())))
0556 && (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>())))
0557 )
0558 {
0559 if (val <= (std::numeric_limits<limb_type>::max)())
0560 {
0561 eval_multiply(result, a, static_cast<limb_type>(val));
0562 }
0563 else
0564 {
0565 #if BOOST_MP_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
0566 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
0567 #else
0568 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
0569 t = val;
0570 #endif
0571 eval_multiply(result, a, t);
0572 }
0573 }
0574
0575 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0576 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
0577 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const double_limb_type& val)
0578 noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const double_limb_type&>()))))
0579 {
0580 eval_multiply(result, result, val);
0581 }
0582
0583 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0584 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0585 eval_multiply(
0586 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0587 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0588 const signed_limb_type& val)
0589 noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const limb_type&>()))))
0590 {
0591 if (val > 0)
0592 eval_multiply(result, a, static_cast<limb_type>(val));
0593 else
0594 {
0595 eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
0596 result.negate();
0597 }
0598 }
0599
0600 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0601 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
0602 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_limb_type& val)
0603 noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const limb_type&>()))))
0604 {
0605 eval_multiply(result, result, val);
0606 }
0607
0608 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0609 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0610 eval_multiply(
0611 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0612 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0613 const signed_double_limb_type& val)
0614 noexcept(
0615 (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const limb_type&>())))
0616 && (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>())))
0617 )
0618 {
0619 if (val > 0)
0620 {
0621 if (val <= (std::numeric_limits<limb_type>::max)())
0622 {
0623 eval_multiply(result, a, static_cast<limb_type>(val));
0624 return;
0625 }
0626 }
0627 else if (val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
0628 {
0629 eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
0630 result.negate();
0631 return;
0632 }
0633 #if BOOST_MP_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
0634 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
0635 #else
0636 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
0637 t = val;
0638 #endif
0639 eval_multiply(result, a, t);
0640 }
0641
0642 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0643 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
0644 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_double_limb_type& val)
0645 noexcept(
0646 (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const limb_type&>())))
0647 && (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>())))
0648 )
0649 {
0650 eval_multiply(result, result, val);
0651 }
0652
0653
0654
0655
0656 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0657 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0658 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && 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 || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)>::type
0659 eval_multiply(
0660 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0661 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0662 {
0663 *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0664 result.sign(result.sign() != o.sign());
0665 result.normalize();
0666 }
0667
0668 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0669 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0670 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>::type
0671 eval_multiply(
0672 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0673 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0674 {
0675 *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0676 result.normalize();
0677 }
0678
0679 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0680 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0681 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && 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 || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)>::type
0682 eval_multiply(
0683 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0684 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0685 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))
0686 {
0687 *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0688 result.sign(a.sign() != b.sign());
0689 result.normalize();
0690 }
0691
0692 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0693 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0694 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>::type
0695 eval_multiply(
0696 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0697 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0698 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))
0699 {
0700 *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0701 result.normalize();
0702 }
0703
0704
0705
0706
0707 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0708 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0709 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0710 eval_multiply(
0711 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0712 signed_double_limb_type a, signed_double_limb_type b)
0713 {
0714 constexpr signed_double_limb_type mask = static_cast<signed_double_limb_type>(~static_cast<limb_type>(0));
0715 constexpr std::size_t limb_bits = static_cast<std::size_t>(sizeof(limb_type) * CHAR_BIT);
0716
0717 bool s = false;
0718 if (a < 0)
0719 {
0720 a = -a;
0721 s = true;
0722 }
0723 if (b < 0)
0724 {
0725 b = -b;
0726 s = !s;
0727 }
0728 double_limb_type w = a & mask;
0729 double_limb_type x = static_cast<double_limb_type>(a >> limb_bits);
0730 double_limb_type y = b & mask;
0731 double_limb_type z = static_cast<double_limb_type>(b >> limb_bits);
0732
0733 result.resize(4, 4);
0734 limb_type* pr = result.limbs();
0735
0736 double_limb_type carry = w * y;
0737 #ifdef __MSVC_RUNTIME_CHECKS
0738 pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0739 carry >>= limb_bits;
0740 carry += w * z + x * y;
0741 pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0742 carry >>= limb_bits;
0743 carry += x * z;
0744 pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0745 pr[3] = static_cast<limb_type>(carry >> limb_bits);
0746 #else
0747 pr[0] = static_cast<limb_type>(carry);
0748 carry >>= limb_bits;
0749 carry += w * z + x * y;
0750 pr[1] = static_cast<limb_type>(carry);
0751 carry >>= limb_bits;
0752 carry += x * z;
0753 pr[2] = static_cast<limb_type>(carry);
0754 pr[3] = static_cast<limb_type>(carry >> limb_bits);
0755 #endif
0756 result.sign(s);
0757 result.normalize();
0758 }
0759
0760 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0761 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0762 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0763 eval_multiply(
0764 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0765 double_limb_type a, double_limb_type b)
0766 {
0767 constexpr signed_double_limb_type mask = static_cast<signed_double_limb_type>(~static_cast<limb_type>(0));
0768 constexpr std::size_t limb_bits = static_cast<std::size_t>(sizeof(limb_type) * CHAR_BIT);
0769
0770 double_limb_type w = a & mask;
0771 double_limb_type x = a >> limb_bits;
0772 double_limb_type y = b & mask;
0773 double_limb_type z = b >> limb_bits;
0774
0775 result.resize(4, 4);
0776 limb_type* pr = result.limbs();
0777
0778 double_limb_type carry = w * y;
0779 #ifdef __MSVC_RUNTIME_CHECKS
0780 pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0781 carry >>= limb_bits;
0782 carry += w * z;
0783 pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0784 carry >>= limb_bits;
0785 pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0786 carry = x * y + pr[1];
0787 pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0788 carry >>= limb_bits;
0789 carry += pr[2] + x * z;
0790 pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0791 pr[3] = static_cast<limb_type>(carry >> limb_bits);
0792 #else
0793 pr[0] = static_cast<limb_type>(carry);
0794 carry >>= limb_bits;
0795 carry += w * z;
0796 pr[1] = static_cast<limb_type>(carry);
0797 carry >>= limb_bits;
0798 pr[2] = static_cast<limb_type>(carry);
0799 carry = x * y + pr[1];
0800 pr[1] = static_cast<limb_type>(carry);
0801 carry >>= limb_bits;
0802 carry += pr[2] + x * z;
0803 pr[2] = static_cast<limb_type>(carry);
0804 pr[3] = static_cast<limb_type>(carry >> limb_bits);
0805 #endif
0806 result.sign(false);
0807 result.normalize();
0808 }
0809
0810 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
0811 std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0812 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0813 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0814 eval_multiply(
0815 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0816 cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
0817 cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
0818 {
0819 using canonical_type = typename boost::multiprecision::detail::canonical<typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::local_limb_type, cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::type;
0820 eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
0821 result.sign(a.sign() != b.sign());
0822 }
0823
0824 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
0825 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_signed<SI>::value && boost::multiprecision::detail::is_integral<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
0826 eval_multiply(
0827 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0828 SI a, SI b)
0829 {
0830 result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
0831 }
0832
0833 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
0834 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
0835 eval_multiply(
0836 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0837 UI a, UI b)
0838 {
0839 result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
0840 }
0841
0842 #ifdef BOOST_MSVC
0843 #pragma warning(pop)
0844 #endif
0845
0846 }}}
0847
0848 #endif