diff options
Diffstat (limited to 'src/third_party/boost-1.60.0/boost/multiprecision/cpp_int/multiply.hpp')
-rw-r--r-- | src/third_party/boost-1.60.0/boost/multiprecision/cpp_int/multiply.hpp | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/third_party/boost-1.60.0/boost/multiprecision/cpp_int/multiply.hpp b/src/third_party/boost-1.60.0/boost/multiprecision/cpp_int/multiply.hpp new file mode 100644 index 00000000000..226bc9d192e --- /dev/null +++ b/src/third_party/boost-1.60.0/boost/multiprecision/cpp_int/multiply.hpp @@ -0,0 +1,439 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ +// +// Comparison operators for cpp_int_backend: +// +#ifndef BOOST_MP_CPP_INT_MUL_HPP +#define BOOST_MP_CPP_INT_MUL_HPP + +namespace boost{ namespace multiprecision{ namespace backends{ + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +inline typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((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); + *p = static_cast<limb_type>(carry); + carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits; + ++p, ++pa; + } + if(carry) + { + unsigned i = result.size(); + result.resize(i + 1, i + 1); + if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (result.size() > i)) + result.limbs()[i] = static_cast<limb_type>(carry); + } + result.sign(a.sign()); + if(!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable) + result.normalize(); +} + +// +// resize_for_carry forces a resize of the underlying buffer only if a previous request +// for "required" elements could possibly have failed, *and* we have checking enabled. +// This will cause an overflow error inside resize(): +// +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/){} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, void>& result, unsigned required) +{ + if(result.size() != required) + result.resize(required, required); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3> +inline typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + // Very simple long multiplication, only usable for small numbers of limb_type's + // but that's the typical use case for this type anyway: + // + // Special cases first: + // + unsigned as = a.size(); + unsigned 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; + } + + result.resize(as + bs, as + bs - 1); + typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs(); + + static const double_limb_type limb_max = ~static_cast<limb_type>(0u); + static const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u); + BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max); + + double_limb_type carry = 0; + std::memset(pr, 0, result.size() * sizeof(limb_type)); + for(unsigned i = 0; i < as; ++i) + { + unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs); + for(unsigned j = 0; j < inner_limit; ++j) + { + BOOST_ASSERT(i+j < result.size()); +#if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100) + BOOST_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_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j])); + carry += pr[i + j]; + pr[i + j] = static_cast<limb_type>(carry); + carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits; + BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value)); + } + resize_for_carry(result, as + bs); // May throw if checking is enabled + if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (i + bs < result.size())) + pr[i + bs] = static_cast<limb_type>(carry); + carry = 0; + } + result.normalize(); + // + // Set the sign of the result: + // + result.sign(a.sign() != b.sign()); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + eval_multiply(result, result, a); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + eval_multiply(result, result, val); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + if(val <= (std::numeric_limits<limb_type>::max)()) + { + eval_multiply(result, a, static_cast<limb_type>(val)); + } + else + { + cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val); + eval_multiply(result, a, t); + } +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + eval_multiply(result, result, val); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + 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 <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + eval_multiply(result, result, val); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +inline typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + 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; + } + cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val); + eval_multiply(result, a, t); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c<!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) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + eval_multiply(result, result, val); +} + +// +// Now over again for trivial cpp_int's: +// +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c< + 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) BOOST_MP_NOEXCEPT_IF((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 <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c< + 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) BOOST_MP_NOEXCEPT_IF((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 <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c< + 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) BOOST_MP_NOEXCEPT_IF((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 <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c< + 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) BOOST_MP_NOEXCEPT_IF((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(); +} + +// +// Special routines for multiplying two integers to obtain a multiprecision result: +// +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c< + !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) +{ + static const signed_double_limb_type mask = ~static_cast<limb_type>(0); + static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; + bool s = false; + double_limb_type w, x, y, z; + if(a < 0) + { + a = -a; + s = true; + } + if(b < 0) + { + b = -b; + s = !s; + } + w = a & mask; + x = a >> limb_bits; + y = b & mask; + z = b >> limb_bits; + + result.resize(4, 4); + limb_type* pr = result.limbs(); + + double_limb_type carry = w * y; + 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); + + result.sign(s); + result.normalize(); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> +BOOST_MP_FORCEINLINE typename enable_if_c< + !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) +{ + static const signed_double_limb_type mask = ~static_cast<limb_type>(0); + static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; + + double_limb_type w, x, y, z; + w = a & mask; + x = a >> limb_bits; + y = b & mask; + z = b >> limb_bits; + + result.resize(4, 4); + limb_type* pr = result.limbs(); + + double_limb_type carry = w * y; + 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); + + result.sign(false); + result.normalize(); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, + unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +BOOST_MP_FORCEINLINE typename enable_if_c< + !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) +{ + typedef 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 canonical_type; + eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs())); + result.sign(a.sign() != b.sign()); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI> +BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<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 <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI> +BOOST_MP_FORCEINLINE typename enable_if_c<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); +} + +}}} // namespaces + +#endif |