Chris@16: /////////////////////////////////////////////////////////////// Chris@16: // Copyright 2012 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ Chris@16: // Chris@16: // Comparison operators for cpp_int_backend: Chris@16: // Chris@16: #ifndef BOOST_MP_CPP_INT_MUL_HPP Chris@16: #define BOOST_MP_CPP_INT_MUL_HPP Chris@16: Chris@16: namespace boost{ namespace multiprecision{ namespace backends{ Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(!val) Chris@16: { Chris@16: result = static_cast(0); Chris@16: return; Chris@16: } Chris@16: if((void*)&a != (void*)&result) Chris@16: result.resize(a.size(), a.size()); Chris@16: double_limb_type carry = 0; Chris@16: typename cpp_int_backend::limb_pointer p = result.limbs(); Chris@16: typename cpp_int_backend::limb_pointer pe = result.limbs() + result.size(); Chris@16: typename cpp_int_backend::const_limb_pointer pa = a.limbs(); Chris@16: while(p != pe) Chris@16: { Chris@16: carry += static_cast(*pa) * static_cast(val); Chris@16: *p = static_cast(carry); Chris@16: carry >>= cpp_int_backend::limb_bits; Chris@16: ++p, ++pa; Chris@16: } Chris@16: if(carry) Chris@16: { Chris@16: unsigned i = result.size(); Chris@16: result.resize(i + 1, i + 1); Chris@16: if(cpp_int_backend::variable || (result.size() > i)) Chris@16: result.limbs()[i] = static_cast(carry); Chris@16: } Chris@16: result.sign(a.sign()); Chris@16: if(!cpp_int_backend::variable) Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: // Chris@16: // resize_for_carry forces a resize of the underlying buffer only if a previous request Chris@16: // for "required" elements could possibly have failed, *and* we have checking enabled. Chris@16: // This will cause an overflow error inside resize(): Chris@16: // Chris@16: template Chris@16: inline void resize_for_carry(cpp_int_backend& /*result*/, unsigned /*required*/){} Chris@16: Chris@16: template Chris@16: inline void resize_for_carry(cpp_int_backend& result, unsigned required) Chris@16: { Chris@16: if(result.size() != required) Chris@16: result.resize(required, required); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_trivial_cpp_int >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const cpp_int_backend& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: // Very simple long multiplication, only usable for small numbers of limb_type's Chris@16: // but that's the typical use case for this type anyway: Chris@16: // Chris@16: // Special cases first: Chris@16: // Chris@16: unsigned as = a.size(); Chris@16: unsigned bs = b.size(); Chris@16: typename cpp_int_backend::const_limb_pointer pa = a.limbs(); Chris@16: typename cpp_int_backend::const_limb_pointer pb = b.limbs(); Chris@16: if(as == 1) Chris@16: { Chris@16: bool s = b.sign() != a.sign(); Chris@16: if(bs == 1) Chris@16: { Chris@16: result = static_cast(*pa) * static_cast(*pb); Chris@16: } Chris@16: else Chris@16: { Chris@16: limb_type l = *pa; Chris@16: eval_multiply(result, b, l); Chris@16: } Chris@16: result.sign(s); Chris@16: return; Chris@16: } Chris@16: if(bs == 1) Chris@16: { Chris@16: bool s = b.sign() != a.sign(); Chris@16: limb_type l = *pb; Chris@16: eval_multiply(result, a, l); Chris@16: result.sign(s); Chris@16: return; Chris@16: } Chris@16: Chris@16: if((void*)&result == (void*)&a) Chris@16: { Chris@16: cpp_int_backend t(a); Chris@16: eval_multiply(result, t, b); Chris@16: return; Chris@16: } Chris@16: if((void*)&result == (void*)&b) Chris@16: { Chris@16: cpp_int_backend t(b); Chris@16: eval_multiply(result, a, t); Chris@16: return; Chris@16: } Chris@16: Chris@16: result.resize(as + bs, as + bs - 1); Chris@16: typename cpp_int_backend::limb_pointer pr = result.limbs(); Chris@16: Chris@16: static const double_limb_type limb_max = ~static_cast(0u); Chris@16: static const double_limb_type double_limb_max = ~static_cast(0u); Chris@16: BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max); Chris@16: Chris@16: double_limb_type carry = 0; Chris@16: std::memset(pr, 0, result.size() * sizeof(limb_type)); Chris@16: for(unsigned i = 0; i < as; ++i) Chris@16: { Chris@16: unsigned inner_limit = cpp_int_backend::variable ? bs : (std::min)(result.size() - i, bs); Chris@16: for(unsigned j = 0; j < inner_limit; ++j) Chris@16: { Chris@16: BOOST_ASSERT(i+j < result.size()); Chris@16: BOOST_ASSERT(!std::numeric_limits::is_specialized Chris@16: || ((std::numeric_limits::max)() - carry Chris@16: > Chris@16: static_cast(cpp_int_backend::max_limb_value) * static_cast(cpp_int_backend::max_limb_value))); Chris@16: carry += static_cast(pa[i]) * static_cast(pb[j]); Chris@16: BOOST_ASSERT(!std::numeric_limits::is_specialized || ((std::numeric_limits::max)() - carry >= pr[i+j])); Chris@16: carry += pr[i + j]; Chris@16: pr[i + j] = static_cast(carry); Chris@16: carry >>= cpp_int_backend::limb_bits; Chris@16: BOOST_ASSERT(carry <= (cpp_int_backend::max_limb_value)); Chris@16: } Chris@16: resize_for_carry(result, as + bs); // May throw if checking is enabled Chris@16: if(cpp_int_backend::variable || (i + bs < result.size())) Chris@16: pr[i + bs] = static_cast(carry); Chris@16: carry = 0; Chris@16: } Chris@16: result.normalize(); Chris@16: // Chris@16: // Set the sign of the result: Chris@16: // Chris@16: result.sign(a.sign() != b.sign()); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_multiply(result, result, a); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_multiply(cpp_int_backend& result, const limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_multiply(result, result, val); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(val <= (std::numeric_limits::max)()) Chris@16: { Chris@16: eval_multiply(result, a, static_cast(val)); Chris@16: } Chris@16: else Chris@16: { Chris@16: cpp_int_backend t(val); Chris@16: eval_multiply(result, a, t); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_multiply(cpp_int_backend& result, const double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_multiply(result, result, val); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const signed_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(val > 0) Chris@16: eval_multiply(result, a, static_cast(val)); Chris@16: else Chris@16: { Chris@101: eval_multiply(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(val))); Chris@16: result.negate(); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_multiply(cpp_int_backend& result, const signed_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_multiply(result, result, val); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const signed_double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(val > 0) Chris@16: { Chris@16: if(val <= (std::numeric_limits::max)()) Chris@16: { Chris@16: eval_multiply(result, a, static_cast(val)); Chris@16: return; Chris@16: } Chris@16: } Chris@16: else if(val >= -static_cast((std::numeric_limits::max)())) Chris@16: { Chris@101: eval_multiply(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(val))); Chris@16: result.negate(); Chris@16: return; Chris@16: } Chris@16: cpp_int_backend t(val); Chris@16: eval_multiply(result, a, t); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_multiply(cpp_int_backend& result, const signed_double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_multiply(result, result, val); Chris@16: } Chris@16: Chris@16: // Chris@16: // Now over again for trivial cpp_int's: Chris@16: // Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && (is_signed_number >::value Chris@16: || is_signed_number >::value) Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.sign(result.sign() != o.sign()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_unsigned_number >::value Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && (is_signed_number >::value Chris@16: || is_signed_number >::value) Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const cpp_int_backend& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.sign(a.sign() != b.sign()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_unsigned_number >::value Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const cpp_int_backend& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: // Chris@16: // Special routines for multiplying two integers to obtain a multiprecision result: Chris@16: // Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: !is_trivial_cpp_int >::value Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: signed_double_limb_type a, signed_double_limb_type b) Chris@16: { Chris@16: static const signed_double_limb_type mask = ~static_cast(0); Chris@16: static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; Chris@16: bool s = false; Chris@16: double_limb_type w, x, y, z; Chris@16: if(a < 0) Chris@16: { Chris@16: a = -a; Chris@16: s = true; Chris@16: } Chris@16: if(b < 0) Chris@16: { Chris@16: b = -b; Chris@16: s = !s; Chris@16: } Chris@16: w = a & mask; Chris@16: x = a >> limb_bits; Chris@16: y = b & mask; Chris@16: z = b >> limb_bits; Chris@16: Chris@16: result.resize(4, 4); Chris@16: limb_type* pr = result.limbs(); Chris@16: Chris@16: double_limb_type carry = w * y; Chris@16: pr[0] = static_cast(carry); Chris@16: carry >>= limb_bits; Chris@16: carry += w * z + x * y; Chris@16: pr[1] = static_cast(carry); Chris@16: carry >>= limb_bits; Chris@16: carry += x * z; Chris@16: pr[2] = static_cast(carry); Chris@16: pr[3] = static_cast(carry >> limb_bits); Chris@16: Chris@16: result.sign(s); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: !is_trivial_cpp_int >::value Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: double_limb_type a, double_limb_type b) Chris@16: { Chris@16: static const signed_double_limb_type mask = ~static_cast(0); Chris@16: static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; Chris@16: Chris@16: double_limb_type w, x, y, z; Chris@16: w = a & mask; Chris@16: x = a >> limb_bits; Chris@16: y = b & mask; Chris@16: z = b >> limb_bits; Chris@16: Chris@16: result.resize(4, 4); Chris@16: limb_type* pr = result.limbs(); Chris@16: Chris@16: double_limb_type carry = w * y; Chris@16: pr[0] = static_cast(carry); Chris@16: carry >>= limb_bits; Chris@16: carry += w * z; Chris@16: pr[1] = static_cast(carry); Chris@16: carry >>= limb_bits; Chris@16: pr[2] = static_cast(carry); Chris@16: carry = x * y + pr[1]; Chris@16: pr[1] = static_cast(carry); Chris@16: carry >>= limb_bits; Chris@16: carry += pr[2] + x * z; Chris@16: pr[2] = static_cast(carry); Chris@16: pr[3] = static_cast(carry >> limb_bits); Chris@16: Chris@16: result.sign(false); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: !is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: >::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: cpp_int_backend const& a, Chris@16: cpp_int_backend const& b) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::local_limb_type, cpp_int_backend >::type canonical_type; Chris@16: eval_multiply(result, static_cast(*a.limbs()), static_cast(*b.limbs())); Chris@16: result.sign(a.sign() != b.sign()); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: SI a, SI b) Chris@16: { Chris@16: result = static_cast(a) * static_cast(b); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type Chris@16: eval_multiply( Chris@16: cpp_int_backend& result, Chris@16: UI a, UI b) Chris@16: { Chris@16: result = static_cast(a) * static_cast(b); Chris@16: } Chris@16: Chris@16: }}} // namespaces Chris@16: Chris@16: #endif