1 ///////////////////////////////////////////////////////////////
2 // Copyright 2012 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
6 // Comparison operators for cpp_int_backend:
8 #ifndef BOOST_MP_CPP_INT_MUL_HPP
9 #define BOOST_MP_CPP_INT_MUL_HPP
11 namespace boost{ namespace multiprecision{ namespace backends{
15 #pragma warning(disable:4127) // conditional expression is constant
18 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>
19 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
21 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
22 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
23 const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
27 result = static_cast<limb_type>(0);
30 if((void*)&a != (void*)&result)
31 result.resize(a.size(), a.size());
32 double_limb_type carry = 0;
33 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
34 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
35 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
38 carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
39 #ifdef __MSVC_RUNTIME_CHECKS
40 *p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
42 *p = static_cast<limb_type>(carry);
44 carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
49 unsigned i = result.size();
50 result.resize(i + 1, i + 1);
51 if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (result.size() > i))
52 result.limbs()[i] = static_cast<limb_type>(carry);
54 result.sign(a.sign());
55 if(!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable)
60 // resize_for_carry forces a resize of the underlying buffer only if a previous request
61 // for "required" elements could possibly have failed, *and* we have checking enabled.
62 // This will cause an overflow error inside resize():
64 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
65 inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/){}
67 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
68 inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, void>& result, unsigned required)
70 if(result.size() != required)
71 result.resize(required, required);
74 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>
75 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
77 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
78 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
79 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))
81 // Very simple long multiplication, only usable for small numbers of limb_type's
82 // but that's the typical use case for this type anyway:
84 // Special cases first:
86 unsigned as = a.size();
87 unsigned bs = b.size();
88 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
89 typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
92 bool s = b.sign() != a.sign();
95 result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
100 eval_multiply(result, b, l);
107 bool s = b.sign() != a.sign();
109 eval_multiply(result, a, l);
114 if((void*)&result == (void*)&a)
116 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
117 eval_multiply(result, t, b);
120 if((void*)&result == (void*)&b)
122 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
123 eval_multiply(result, a, t);
127 result.resize(as + bs, as + bs - 1);
128 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
130 static const double_limb_type limb_max = ~static_cast<limb_type>(0u);
131 static const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u);
132 BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max);
134 double_limb_type carry = 0;
135 std::memset(pr, 0, result.size() * sizeof(limb_type));
136 for(unsigned i = 0; i < as; ++i)
138 unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
139 for(unsigned j = 0; j < inner_limit; ++j)
141 BOOST_ASSERT(i+j < result.size());
142 #if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
143 BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized
144 || ((std::numeric_limits<double_limb_type>::max)() - carry
146 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)));
148 carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
149 BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j]));
151 #ifdef __MSVC_RUNTIME_CHECKS
152 pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
154 pr[i + j] = static_cast<limb_type>(carry);
156 carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
157 BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
159 resize_for_carry(result, as + bs); // May throw if checking is enabled
160 if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (i + bs < result.size()))
161 pr[i + bs] = static_cast<limb_type>(carry);
166 // Set the sign of the result:
168 result.sign(a.sign() != b.sign());
171 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>
172 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
174 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
175 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))
177 eval_multiply(result, result, a);
180 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
181 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
182 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))
184 eval_multiply(result, result, val);
187 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>
188 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
190 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
191 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
192 const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
194 if(val <= (std::numeric_limits<limb_type>::max)())
196 eval_multiply(result, a, static_cast<limb_type>(val));
200 #if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
201 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
203 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
206 eval_multiply(result, a, t);
210 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
211 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
212 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))
214 eval_multiply(result, result, val);
217 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>
218 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
220 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
221 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
222 const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
225 eval_multiply(result, a, static_cast<limb_type>(val));
228 eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
233 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
234 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
235 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))
237 eval_multiply(result, result, val);
240 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>
241 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
243 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
244 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
245 const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
249 if(val <= (std::numeric_limits<limb_type>::max)())
251 eval_multiply(result, a, static_cast<limb_type>(val));
255 else if(val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
257 eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
261 #if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
262 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
264 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
267 eval_multiply(result, a, t);
270 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
271 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
272 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))
274 eval_multiply(result, result, val);
278 // Now over again for trivial cpp_int's:
280 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
281 BOOST_MP_FORCEINLINE typename enable_if_c<
282 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
283 && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
284 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
285 || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
288 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
289 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))
291 *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
292 result.sign(result.sign() != o.sign());
296 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
297 BOOST_MP_FORCEINLINE typename enable_if_c<
298 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
299 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
302 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
303 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))
305 *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
309 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
310 BOOST_MP_FORCEINLINE typename enable_if_c<
311 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
312 && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
313 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
314 || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
317 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
318 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
319 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))
321 *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
322 result.sign(a.sign() != b.sign());
326 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
327 BOOST_MP_FORCEINLINE typename enable_if_c<
328 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
329 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
332 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
333 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
334 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))
336 *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
341 // Special routines for multiplying two integers to obtain a multiprecision result:
343 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
344 BOOST_MP_FORCEINLINE typename enable_if_c<
345 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
348 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
349 signed_double_limb_type a, signed_double_limb_type b)
351 static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
352 static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
354 double_limb_type w, x, y, z;
371 limb_type* pr = result.limbs();
373 double_limb_type carry = w * y;
374 #ifdef __MSVC_RUNTIME_CHECKS
375 pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
377 carry += w * z + x * y;
378 pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
381 pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
382 pr[3] = static_cast<limb_type>(carry >> limb_bits);
384 pr[0] = static_cast<limb_type>(carry);
386 carry += w * z + x * y;
387 pr[1] = static_cast<limb_type>(carry);
390 pr[2] = static_cast<limb_type>(carry);
391 pr[3] = static_cast<limb_type>(carry >> limb_bits);
397 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
398 BOOST_MP_FORCEINLINE typename enable_if_c<
399 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
402 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
403 double_limb_type a, double_limb_type b)
405 static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
406 static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
408 double_limb_type w, x, y, z;
415 limb_type* pr = result.limbs();
417 double_limb_type carry = w * y;
418 #ifdef __MSVC_RUNTIME_CHECKS
419 pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
422 pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
424 pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
425 carry = x * y + pr[1];
426 pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
428 carry += pr[2] + x * z;
429 pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
430 pr[3] = static_cast<limb_type>(carry >> limb_bits);
432 pr[0] = static_cast<limb_type>(carry);
435 pr[1] = static_cast<limb_type>(carry);
437 pr[2] = static_cast<limb_type>(carry);
438 carry = x * y + pr[1];
439 pr[1] = static_cast<limb_type>(carry);
441 carry += pr[2] + x * z;
442 pr[2] = static_cast<limb_type>(carry);
443 pr[3] = static_cast<limb_type>(carry >> limb_bits);
449 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
450 unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
451 BOOST_MP_FORCEINLINE typename enable_if_c<
452 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
453 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
454 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
457 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
458 cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
459 cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
461 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;
462 eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
463 result.sign(a.sign() != b.sign());
466 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
467 BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
469 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
472 result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
475 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
476 BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
478 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
481 result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);