/////////////////////////////////////////////////////////////// // Copyright 2012 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt // // 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 { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant #endif template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value && !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { if (!val) { result = static_cast(0); return; } if ((void*)&a != (void*)&result) result.resize(a.size(), a.size()); double_limb_type carry = 0; typename cpp_int_backend::limb_pointer p = result.limbs(); typename cpp_int_backend::limb_pointer pe = result.limbs() + result.size(); typename cpp_int_backend::const_limb_pointer pa = a.limbs(); while (p != pe) { carry += static_cast(*pa) * static_cast(val); #ifdef __MSVC_RUNTIME_CHECKS *p = static_cast(carry & ~static_cast(0)); #else *p = static_cast(carry); #endif carry >>= cpp_int_backend::limb_bits; ++p, ++pa; } if (carry) { unsigned i = result.size(); result.resize(i + 1, i + 1); if (result.size() > i) result.limbs()[i] = static_cast(carry); } result.sign(a.sign()); if (!cpp_int_backend::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 inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend& /*result*/, unsigned /*required*/) {} template inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend& result, unsigned required) { if (result.size() < required) result.resize(required, required); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value && !is_trivial_cpp_int >::value && !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const cpp_int_backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::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::const_limb_pointer pa = a.limbs(); typename cpp_int_backend::const_limb_pointer pb = b.limbs(); if (as == 1) { bool s = b.sign() != a.sign(); if (bs == 1) { result = static_cast(*pa) * static_cast(*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 t(a); eval_multiply(result, t, b); return; } if ((void*)&result == (void*)&b) { cpp_int_backend t(b); eval_multiply(result, a, t); return; } result.resize(as + bs, as + bs - 1); typename cpp_int_backend::limb_pointer pr = result.limbs(); #ifdef BOOST_NO_CXX14_CONSTEXPR static const double_limb_type limb_max = ~static_cast(0u); static const double_limb_type double_limb_max = ~static_cast(0u); #else constexpr const double_limb_type limb_max = ~static_cast(0u); constexpr const double_limb_type double_limb_max = ~static_cast(0u); #endif BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max); double_limb_type carry = 0; #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION if (BOOST_MP_IS_CONST_EVALUATED(as)) { for (unsigned i = 0; i < result.size(); ++i) pr[i] = 0; } else #endif std::memset(pr, 0, result.size() * sizeof(limb_type)); for (unsigned i = 0; i < as; ++i) { unsigned inner_limit = cpp_int_backend::variable ? bs : (std::min)(result.size() - i, bs); unsigned j = 0; for (; 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::is_specialized || ((std::numeric_limits::max)() - carry > static_cast(cpp_int_backend::max_limb_value) * static_cast(cpp_int_backend::max_limb_value))); #endif carry += static_cast(pa[i]) * static_cast(pb[j]); BOOST_ASSERT(!std::numeric_limits::is_specialized || ((std::numeric_limits::max)() - carry >= pr[i + j])); carry += pr[i + j]; #ifdef __MSVC_RUNTIME_CHECKS pr[i + j] = static_cast(carry & ~static_cast(0)); #else pr[i + j] = static_cast(carry); #endif carry >>= cpp_int_backend::limb_bits; BOOST_ASSERT(carry <= (cpp_int_backend::max_limb_value)); } if (carry) { resize_for_carry(result, i + j + 1); // May throw if checking is enabled if (i + j < result.size()) #ifdef __MSVC_RUNTIME_CHECKS pr[i + j] = static_cast(carry & ~static_cast(0)); #else pr[i + j] = static_cast(carry); #endif } carry = 0; } result.normalize(); // // Set the sign of the result: // result.sign(a.sign() != b.sign()); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value && !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { eval_multiply(result, result, a); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value>::type eval_multiply(cpp_int_backend& result, const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { eval_multiply(result, result, val); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value && !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { if (val <= (std::numeric_limits::max)()) { eval_multiply(result, a, static_cast(val)); } else { #if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE) cpp_int_backend t(val); #else cpp_int_backend t; t = val; #endif eval_multiply(result, a, t); } } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value>::type eval_multiply(cpp_int_backend& result, const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { eval_multiply(result, result, val); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value && !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { if (val > 0) eval_multiply(result, a, static_cast(val)); else { eval_multiply(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(val))); result.negate(); } } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value>::type eval_multiply(cpp_int_backend& result, const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { eval_multiply(result, result, val); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value && !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { if (val > 0) { if (val <= (std::numeric_limits::max)()) { eval_multiply(result, a, static_cast(val)); return; } } else if (val >= -static_cast((std::numeric_limits::max)())) { eval_multiply(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(val))); result.negate(); return; } #if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE) cpp_int_backend t(val); #else cpp_int_backend t; t = val; #endif eval_multiply(result, a, t); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c >::value>::type eval_multiply(cpp_int_backend& result, const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { eval_multiply(result, result, val); } // // Now over again for trivial cpp_int's: // template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && (is_signed_number >::value || is_signed_number >::value)>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); result.sign(result.sign() != o.sign()); result.normalize(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< is_trivial_cpp_int >::value && is_unsigned_number >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); result.normalize(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && (is_signed_number >::value || is_signed_number >::value)>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const cpp_int_backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend::checked_type()); result.sign(a.sign() != b.sign()); result.normalize(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< is_trivial_cpp_int >::value && is_unsigned_number >::value>::type eval_multiply( cpp_int_backend& result, const cpp_int_backend& a, const cpp_int_backend& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) { *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend::checked_type()); result.normalize(); } // // Special routines for multiplying two integers to obtain a multiprecision result: // template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, signed_double_limb_type a, signed_double_limb_type b) { #ifdef BOOST_NO_CXX14_CONSTEXPR static const signed_double_limb_type mask = ~static_cast(0); static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; #else constexpr const signed_double_limb_type mask = ~static_cast(0); constexpr const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; #endif 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 = 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(carry & ~static_cast(0)); carry >>= limb_bits; carry += w * z + x * y; pr[1] = static_cast(carry & ~static_cast(0)); carry >>= limb_bits; carry += x * z; pr[2] = static_cast(carry & ~static_cast(0)); pr[3] = static_cast(carry >> limb_bits); #else pr[0] = static_cast(carry); carry >>= limb_bits; carry += w * z + x * y; pr[1] = static_cast(carry); carry >>= limb_bits; carry += x * z; pr[2] = static_cast(carry); pr[3] = static_cast(carry >> limb_bits); #endif result.sign(s); result.normalize(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< !is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, double_limb_type a, double_limb_type b) { #ifdef BOOST_NO_CXX14_CONSTEXPR static const signed_double_limb_type mask = ~static_cast(0); static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; #else constexpr const signed_double_limb_type mask = ~static_cast(0); constexpr const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; #endif 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(carry & ~static_cast(0)); carry >>= limb_bits; carry += w * z; pr[1] = static_cast(carry & ~static_cast(0)); carry >>= limb_bits; pr[2] = static_cast(carry & ~static_cast(0)); carry = x * y + pr[1]; pr[1] = static_cast(carry & ~static_cast(0)); carry >>= limb_bits; carry += pr[2] + x * z; pr[2] = static_cast(carry & ~static_cast(0)); pr[3] = static_cast(carry >> limb_bits); #else pr[0] = static_cast(carry); carry >>= limb_bits; carry += w * z; pr[1] = static_cast(carry); carry >>= limb_bits; pr[2] = static_cast(carry); carry = x * y + pr[1]; pr[1] = static_cast(carry); carry >>= limb_bits; carry += pr[2] + x * z; pr[2] = static_cast(carry); pr[3] = static_cast(carry >> limb_bits); #endif result.sign(false); result.normalize(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< !is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && is_trivial_cpp_int >::value>::type eval_multiply( cpp_int_backend& result, cpp_int_backend const& a, cpp_int_backend const& b) { typedef typename boost::multiprecision::detail::canonical::local_limb_type, cpp_int_backend >::type canonical_type; eval_multiply(result, static_cast(*a.limbs()), static_cast(*b.limbs())); result.sign(a.sign() != b.sign()); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type eval_multiply( cpp_int_backend& result, SI a, SI b) { result = static_cast(a) * static_cast(b); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type eval_multiply( cpp_int_backend& result, UI a, UI b) { result = static_cast(a) * static_cast(b); } #ifdef _MSC_VER #pragma warning(pop) #endif }}} // namespace boost::multiprecision::backends #endif