123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 |
- #ifndef BOOST_MP_CPP_INT_MULTIPLY_HPP
- #define BOOST_MP_CPP_INT_MULTIPLY_HPP
- #include <limits>
- #include <boost/multiprecision/detail/standalone_config.hpp>
- #include <boost/multiprecision/detail/endian.hpp>
- #include <boost/multiprecision/detail/assert.hpp>
- #include <boost/multiprecision/integer.hpp>
- namespace boost { namespace multiprecision { namespace backends {
- #ifdef BOOST_MSVC
- #pragma warning(push)
- #pragma warning(disable : 4127)
- #endif
- 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>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- const limb_type& val) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
- {
- if (!val)
- {
- result = static_cast<limb_type>(0);
- return;
- }
- if ((void*)&a != (void*)&result)
- result.resize(a.size(), a.size());
- double_limb_type carry = 0;
- typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
- typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
- typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
- while (p != pe)
- {
- carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
- #ifdef __MSVC_RUNTIME_CHECKS
- *p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- #else
- *p = static_cast<limb_type>(carry);
- #endif
- carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
- ++p, ++pa;
- }
- if (carry)
- {
- std::size_t i = result.size();
- result.resize(i + 1, i + 1);
- if (result.size() > i)
- result.limbs()[i] = static_cast<limb_type>(carry);
- }
- result.sign(a.sign());
- if (is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
- result.normalize();
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, std::size_t /*required*/) {}
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, class Allocator1>
- inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, Allocator1>& result, std::size_t required)
- {
- if (result.size() < required)
- result.resize(required, required);
- }
- #ifdef BOOST_MP_KARATSUBA_CUTOFF
- const size_t karatsuba_cutoff = BOOST_MP_KARATSUBA_CUTOFF;
- #else
- const size_t karatsuba_cutoff = 40;
- #endif
- template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
- inline void multiply_karatsuba(
- cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& result,
- const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a,
- const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& b,
- typename cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>::scoped_shared_storage& storage)
- {
- using cpp_int_type = cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>;
- std::size_t as = a.size();
- std::size_t bs = b.size();
-
-
-
-
- if ((as < karatsuba_cutoff) || (bs < karatsuba_cutoff))
- {
- eval_multiply(result, a, b);
- return;
- }
-
-
-
- std::size_t n = (as > bs ? as : bs) / 2 + 1;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- std::size_t sz = (std::min)(as, n);
- const cpp_int_type a_l(a.limbs(), 0, sz);
- sz = (std::min)(bs, n);
- const cpp_int_type b_l(b.limbs(), 0, sz);
- limb_type zero = 0;
- const cpp_int_type a_h(as > n ? a.limbs() + n : &zero, 0, as > n ? as - n : 1);
- const cpp_int_type b_h(bs > n ? b.limbs() + n : &zero, 0, bs > n ? bs - n : 1);
-
-
-
-
-
-
-
-
-
-
- cpp_int_type t1(storage, 2 * n + 2);
- cpp_int_type t2(storage, n + 1);
- cpp_int_type t3(storage, n + 1);
-
-
-
-
-
-
-
-
- cpp_int_type result_low(result.limbs(), 0, 2 * n);
- cpp_int_type result_high(result.limbs(), 2 * n, result.size() - 2 * n);
-
-
-
- multiply_karatsuba(result_low, a_l, b_l, storage);
-
-
-
-
-
-
-
- for (std::size_t i = result_low.size(); i < 2 * n; ++i)
- result.limbs()[i] = 0;
-
-
-
- multiply_karatsuba(result_high, a_h, b_h, storage);
- for (std::size_t i = result_high.size() + 2 * n; i < result.size(); ++i)
- result.limbs()[i] = 0;
-
-
-
- add_unsigned(t2, a_l, a_h);
- add_unsigned(t3, b_l, b_h);
- multiply_karatsuba(t1, t2, t3, storage);
-
-
-
-
-
-
-
-
- subtract_unsigned(t1, t1, result_high);
- subtract_unsigned(t1, t1, result_low);
-
-
-
-
-
- cpp_int_type result_alias(result.limbs(), n, result.size() - n);
- add_unsigned(result_alias, result_alias, t1);
-
-
-
- storage.deallocate(t1.capacity() + t2.capacity() + t3.capacity());
- result.normalize();
- }
- inline std::size_t karatsuba_storage_size(std::size_t s)
- {
-
-
-
-
-
-
-
-
-
-
- return 5 * s;
- }
- template <std::size_t MinBits, std::size_t MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
- inline typename std::enable_if<!is_fixed_precision<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value>::type
- setup_karatsuba(
- cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result,
- const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& a,
- const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& b)
- {
- std::size_t as = a.size();
- std::size_t bs = b.size();
- std::size_t s = as > bs ? as : bs;
- std::size_t storage_size = karatsuba_storage_size(s);
- if (storage_size < 300)
- {
-
-
-
-
-
- limb_type limbs[300];
- typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::scoped_shared_storage storage(limbs, storage_size);
- multiply_karatsuba(result, a, b, storage);
- }
- else
- {
- typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::scoped_shared_storage storage(result.allocator(), storage_size);
- multiply_karatsuba(result, a, b, storage);
- }
- }
- 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>
- 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
- setup_karatsuba(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
- {
-
-
-
-
-
-
-
-
- using variable_precision_type = cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> >;
- variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
- std::size_t as = a.size();
- std::size_t bs = b.size();
- std::size_t s = as > bs ? as : bs;
- std::size_t sz = as + bs;
- std::size_t storage_size = karatsuba_storage_size(s);
- if (!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || (sz * sizeof(limb_type) * CHAR_BIT <= MaxBits1))
- {
-
- result.resize(sz, sz);
- variable_precision_type t(result.limbs(), 0, result.size());
- typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
- multiply_karatsuba(t, a_t, b_t, storage);
- result.resize(t.size(), t.size());
- }
- else
- {
-
-
-
-
- typename variable_precision_type::scoped_shared_storage storage(variable_precision_type::allocator_type(), sz + storage_size);
- variable_precision_type t(storage, sz);
- multiply_karatsuba(t, a_t, b_t, storage);
-
-
-
- result = t;
- }
- }
- 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>
- 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
- setup_karatsuba(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
- {
-
-
-
- using variable_precision_type = cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> >;
- variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
- std::size_t as = a.size();
- std::size_t bs = b.size();
- std::size_t s = as > bs ? as : bs;
- std::size_t sz = as + bs;
- std::size_t storage_size = karatsuba_storage_size(s);
- result.resize(sz, sz);
- variable_precision_type t(result.limbs(), 0, result.size());
- typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
- multiply_karatsuba(t, a_t, b_t, storage);
- }
- 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>
- inline BOOST_MP_CXX14_CONSTEXPR void
- eval_multiply_comba(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- 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))
- {
-
-
-
-
-
- std::ptrdiff_t as = a.size(),
- bs = b.size(),
- rs = result.size();
- typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
- double_limb_type carry = 0,
- temp = 0;
- limb_type overflow = 0;
- const std::size_t limb_bits = sizeof(limb_type) * CHAR_BIT;
- const bool must_throw = rs < as + bs - 1;
- for (std::ptrdiff_t r = 0, lim = (std::min)(rs, as + bs - 1); r < lim; ++r, overflow = 0)
- {
- std::ptrdiff_t i = r >= as ? as - 1 : r,
- j = r - i,
- k = i < bs - j ? i + 1 : bs - j;
- typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs() + i;
- typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs() + j;
- temp = carry;
- carry += static_cast<double_limb_type>(*(pa)) * (*(pb));
- overflow += carry < temp;
- for (--k; k; k--)
- {
- temp = carry;
- carry += static_cast<double_limb_type>(*(--pa)) * (*(++pb));
- overflow += carry < temp;
- }
- *(pr++) = static_cast<limb_type>(carry);
- carry = (static_cast<double_limb_type>(overflow) << limb_bits) | (carry >> limb_bits);
- }
- if (carry || must_throw)
- {
- resize_for_carry(result, as + bs);
- if (static_cast<int>(result.size()) >= as + bs)
- *pr = static_cast<limb_type>(carry);
- }
- }
- 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>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- 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
- && (karatsuba_cutoff * sizeof(limb_type) * CHAR_BIT > MaxBits1)
- && (karatsuba_cutoff * sizeof(limb_type)* CHAR_BIT > MaxBits2)
- && (karatsuba_cutoff * sizeof(limb_type)* CHAR_BIT > MaxBits3)))
- {
-
-
-
-
-
- std::size_t as = a.size();
- std::size_t bs = b.size();
- typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
- typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
- if (as == 1)
- {
- bool s = b.sign() != a.sign();
- if (bs == 1)
- {
- result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
- }
- else
- {
- limb_type l = *pa;
- eval_multiply(result, b, l);
- }
- result.sign(s);
- return;
- }
- if (bs == 1)
- {
- bool s = b.sign() != a.sign();
- limb_type l = *pb;
- eval_multiply(result, a, l);
- result.sign(s);
- return;
- }
- if ((void*)&result == (void*)&a)
- {
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
- eval_multiply(result, t, b);
- return;
- }
- if ((void*)&result == (void*)&b)
- {
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
- eval_multiply(result, a, t);
- return;
- }
- constexpr double_limb_type limb_max = static_cast<double_limb_type>(~static_cast<limb_type>(0u));
- constexpr double_limb_type double_limb_max = static_cast<double_limb_type>(~static_cast<double_limb_type>(0u));
- result.resize(as + bs, as + bs - 1);
- #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
- if (!BOOST_MP_IS_CONST_EVALUATED(as) && (as >= karatsuba_cutoff && bs >= karatsuba_cutoff))
- #else
- if (as >= karatsuba_cutoff && bs >= karatsuba_cutoff)
- #endif
- {
- setup_karatsuba(result, a, b);
-
-
-
- result.sign(a.sign() != b.sign());
- return;
- }
- typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
- static_assert(double_limb_max - 2 * limb_max >= limb_max * limb_max, "failed limb size sanity check");
- #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
- if (BOOST_MP_IS_CONST_EVALUATED(as))
- {
- for (std::size_t i = 0; i < result.size(); ++i)
- pr[i] = 0;
- }
- else
- #endif
- std::memset(pr, 0, result.size() * sizeof(limb_type));
- #if defined(BOOST_MP_COMBA)
-
-
-
-
-
- eval_multiply_comba(result, a, b);
- #else
- double_limb_type carry = 0;
- for (std::size_t i = 0; i < as; ++i)
- {
- BOOST_MP_ASSERT(result.size() > i);
- std::size_t inner_limit = !is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value ? bs : (std::min)(result.size() - i, bs);
- std::size_t j = 0;
- for (; j < inner_limit; ++j)
- {
- BOOST_MP_ASSERT(i + j < result.size());
- #if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
- BOOST_MP_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >
- 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)));
- #endif
- carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
- BOOST_MP_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i + j]));
- carry += pr[i + j];
- #ifdef __MSVC_RUNTIME_CHECKS
- pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- #else
- pr[i + j] = static_cast<limb_type>(carry);
- #endif
- carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
- BOOST_MP_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
- }
- if (carry)
- {
- resize_for_carry(result, i + j + 1);
- if (i + j < result.size())
- #ifdef __MSVC_RUNTIME_CHECKS
- pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- #else
- pr[i + j] = static_cast<limb_type>(carry);
- #endif
- }
- carry = 0;
- }
- #endif
- result.normalize();
-
-
-
- result.sign(a.sign() != b.sign());
- }
- 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>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a)
- 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>&>()))))
- {
- eval_multiply(result, result, a);
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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
- eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& val)
- 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&>()))))
- {
- eval_multiply(result, result, val);
- }
- 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>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- const double_limb_type& val)
- 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&>())))
- && (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>&>())))
- )
- {
- if (val <= (std::numeric_limits<limb_type>::max)())
- {
- eval_multiply(result, a, static_cast<limb_type>(val));
- }
- else
- {
- #if BOOST_MP_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
- #else
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
- t = val;
- #endif
- eval_multiply(result, a, t);
- }
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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
- eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const double_limb_type& val)
- 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&>()))))
- {
- eval_multiply(result, result, val);
- }
- 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>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- const signed_limb_type& val)
- 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&>()))))
- {
- if (val > 0)
- eval_multiply(result, a, static_cast<limb_type>(val));
- else
- {
- eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
- result.negate();
- }
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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
- eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_limb_type& val)
- 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&>()))))
- {
- eval_multiply(result, result, val);
- }
- 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>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
- const signed_double_limb_type& val)
- 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&>())))
- && (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>&>())))
- )
- {
- if (val > 0)
- {
- if (val <= (std::numeric_limits<limb_type>::max)())
- {
- eval_multiply(result, a, static_cast<limb_type>(val));
- return;
- }
- }
- else if (val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
- {
- eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
- result.negate();
- return;
- }
- #if BOOST_MP_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
- #else
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
- t = val;
- #endif
- eval_multiply(result, a, t);
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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
- eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_double_limb_type& val)
- 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&>())))
- && (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>&>())))
- )
- {
- eval_multiply(result, result, val);
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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<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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- 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))
- {
- *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
- result.sign(result.sign() != o.sign());
- result.normalize();
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- 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))
- {
- *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
- result.normalize();
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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<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
- eval_multiply(
- 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))
- {
- *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
- result.sign(a.sign() != b.sign());
- result.normalize();
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
- eval_multiply(
- 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))
- {
- *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
- result.normalize();
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- signed_double_limb_type a, signed_double_limb_type b)
- {
- constexpr signed_double_limb_type mask = static_cast<signed_double_limb_type>(~static_cast<limb_type>(0));
- constexpr std::size_t limb_bits = static_cast<std::size_t>(sizeof(limb_type) * CHAR_BIT);
- bool s = false;
- if (a < 0)
- {
- a = -a;
- s = true;
- }
- if (b < 0)
- {
- b = -b;
- s = !s;
- }
- double_limb_type w = a & mask;
- double_limb_type x = static_cast<double_limb_type>(a >> limb_bits);
- double_limb_type y = b & mask;
- double_limb_type z = static_cast<double_limb_type>(b >> limb_bits);
- result.resize(4, 4);
- limb_type* pr = result.limbs();
- double_limb_type carry = w * y;
- #ifdef __MSVC_RUNTIME_CHECKS
- pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- carry >>= limb_bits;
- carry += w * z + x * y;
- pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- carry >>= limb_bits;
- carry += x * z;
- pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- pr[3] = static_cast<limb_type>(carry >> limb_bits);
- #else
- pr[0] = static_cast<limb_type>(carry);
- carry >>= limb_bits;
- carry += w * z + x * y;
- pr[1] = static_cast<limb_type>(carry);
- carry >>= limb_bits;
- carry += x * z;
- pr[2] = static_cast<limb_type>(carry);
- pr[3] = static_cast<limb_type>(carry >> limb_bits);
- #endif
- result.sign(s);
- result.normalize();
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- double_limb_type a, double_limb_type b)
- {
- constexpr signed_double_limb_type mask = static_cast<signed_double_limb_type>(~static_cast<limb_type>(0));
- constexpr std::size_t limb_bits = static_cast<std::size_t>(sizeof(limb_type) * CHAR_BIT);
- double_limb_type w = a & mask;
- double_limb_type x = a >> limb_bits;
- double_limb_type y = b & mask;
- double_limb_type z = b >> limb_bits;
- result.resize(4, 4);
- limb_type* pr = result.limbs();
- double_limb_type carry = w * y;
- #ifdef __MSVC_RUNTIME_CHECKS
- pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- carry >>= limb_bits;
- carry += w * z;
- pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- carry >>= limb_bits;
- pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- carry = x * y + pr[1];
- pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- carry >>= limb_bits;
- carry += pr[2] + x * z;
- pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
- pr[3] = static_cast<limb_type>(carry >> limb_bits);
- #else
- pr[0] = static_cast<limb_type>(carry);
- carry >>= limb_bits;
- carry += w * z;
- pr[1] = static_cast<limb_type>(carry);
- carry >>= limb_bits;
- pr[2] = static_cast<limb_type>(carry);
- carry = x * y + pr[1];
- pr[1] = static_cast<limb_type>(carry);
- carry >>= limb_bits;
- carry += pr[2] + x * z;
- pr[2] = static_cast<limb_type>(carry);
- pr[3] = static_cast<limb_type>(carry >> limb_bits);
- #endif
- result.sign(false);
- result.normalize();
- }
- 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>
- 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 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
- cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
- {
- 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;
- eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
- result.sign(a.sign() != b.sign());
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- SI a, SI b)
- {
- result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
- }
- template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
- 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
- eval_multiply(
- cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
- UI a, UI b)
- {
- result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
- }
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- }}}
- #endif
|