| /////////////////////////////////////////////////////////////// |
| // 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_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_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()); |
| 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))); |
| 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_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_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_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_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_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_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_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_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_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_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_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_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 |