Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / multiprecision / cpp_int / multiply.hpp
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 https://www.boost.org/LICENSE_1_0.txt
5 //
6 // Comparison operators for cpp_int_backend:
7 //
8 #ifndef BOOST_MP_CPP_INT_MUL_HPP
9 #define BOOST_MP_CPP_INT_MUL_HPP
10
11 namespace boost { namespace multiprecision { namespace backends {
12
13 #ifdef _MSC_VER
14 #pragma warning(push)
15 #pragma warning(disable : 4127) // conditional expression is constant
16 #endif
17
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 BOOST_MP_CXX14_CONSTEXPR 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
20 eval_multiply(
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))
24 {
25    if (!val)
26    {
27       result = static_cast<limb_type>(0);
28       return;
29    }
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();
36    while (p != pe)
37    {
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));
41 #else
42       *p = static_cast<limb_type>(carry);
43 #endif
44       carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
45       ++p, ++pa;
46    }
47    if (carry)
48    {
49       unsigned i = result.size();
50       result.resize(i + 1, i + 1);
51       if (result.size() > i)
52          result.limbs()[i] = static_cast<limb_type>(carry);
53    }
54    result.sign(a.sign());
55    if (!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable)
56       result.normalize();
57 }
58
59 //
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():
63 //
64 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
65 inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/) {}
66
67 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, class Allocator1>
68 inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, Allocator1>& result, unsigned required)
69 {
70    if (result.size() < required)
71       result.resize(required, required);
72 }
73
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 BOOST_MP_CXX14_CONSTEXPR 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
76 eval_multiply(
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))
80 {
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:
83    //
84    // Special cases first:
85    //
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();
90    if (as == 1)
91    {
92       bool s = b.sign() != a.sign();
93       if (bs == 1)
94       {
95          result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
96       }
97       else
98       {
99          limb_type l = *pa;
100          eval_multiply(result, b, l);
101       }
102       result.sign(s);
103       return;
104    }
105    if (bs == 1)
106    {
107       bool      s = b.sign() != a.sign();
108       limb_type l = *pb;
109       eval_multiply(result, a, l);
110       result.sign(s);
111       return;
112    }
113
114    if ((void*)&result == (void*)&a)
115    {
116       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
117       eval_multiply(result, t, b);
118       return;
119    }
120    if ((void*)&result == (void*)&b)
121    {
122       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
123       eval_multiply(result, a, t);
124       return;
125    }
126
127    result.resize(as + bs, as + bs - 1);
128    typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
129 #ifdef BOOST_NO_CXX14_CONSTEXPR
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 #else
133    constexpr const double_limb_type limb_max = ~static_cast<limb_type>(0u);
134    constexpr const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u);
135 #endif
136    BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max);
137
138    double_limb_type carry = 0;
139 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
140    if (BOOST_MP_IS_CONST_EVALUATED(as))
141    {
142       for (unsigned i = 0; i < result.size(); ++i)
143          pr[i] = 0;
144    }
145    else
146 #endif
147    std::memset(pr, 0, result.size() * sizeof(limb_type));
148    for (unsigned i = 0; i < as; ++i)
149    {
150       unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
151       unsigned j = 0;
152       for (; j < inner_limit; ++j)
153       {
154          BOOST_ASSERT(i + j < result.size());
155 #if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
156          BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >
157                                                                                  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)));
158 #endif
159          carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
160          BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i + j]));
161          carry += pr[i + j];
162 #ifdef __MSVC_RUNTIME_CHECKS
163          pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
164 #else
165          pr[i + j] = static_cast<limb_type>(carry);
166 #endif
167          carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
168          BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
169       }
170       if (carry)
171       {
172          resize_for_carry(result, i + j + 1); // May throw if checking is enabled
173          if (i + j < result.size())
174 #ifdef __MSVC_RUNTIME_CHECKS
175             pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
176 #else
177             pr[i + j] = static_cast<limb_type>(carry);
178 #endif
179       }
180       carry = 0;
181    }
182    result.normalize();
183    //
184    // Set the sign of the result:
185    //
186    result.sign(a.sign() != b.sign());
187 }
188
189 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>
190 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR 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
191 eval_multiply(
192     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
193     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))
194 {
195    eval_multiply(result, result, a);
196 }
197
198 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
199 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
200 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))
201 {
202    eval_multiply(result, result, val);
203 }
204
205 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>
206 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR 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
207 eval_multiply(
208     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
209     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
210     const double_limb_type&                                                     val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
211 {
212    if (val <= (std::numeric_limits<limb_type>::max)())
213    {
214       eval_multiply(result, a, static_cast<limb_type>(val));
215    }
216    else
217    {
218 #if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
219       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
220 #else
221       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
222       t = val;
223 #endif
224       eval_multiply(result, a, t);
225    }
226 }
227
228 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
229 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
230 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))
231 {
232    eval_multiply(result, result, val);
233 }
234
235 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>
236 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR 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
237 eval_multiply(
238     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
239     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
240     const signed_limb_type&                                                     val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
241 {
242    if (val > 0)
243       eval_multiply(result, a, static_cast<limb_type>(val));
244    else
245    {
246       eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
247       result.negate();
248    }
249 }
250
251 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
252 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
253 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))
254 {
255    eval_multiply(result, result, val);
256 }
257
258 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>
259 inline BOOST_MP_CXX14_CONSTEXPR 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
260 eval_multiply(
261     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
262     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
263     const signed_double_limb_type&                                              val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
264 {
265    if (val > 0)
266    {
267       if (val <= (std::numeric_limits<limb_type>::max)())
268       {
269          eval_multiply(result, a, static_cast<limb_type>(val));
270          return;
271       }
272    }
273    else if (val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
274    {
275       eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
276       result.negate();
277       return;
278    }
279 #if BOOST_ENDIAN_LITTLE_BYTE && !defined(BOOST_MP_TEST_NO_LE)
280    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
281 #else
282    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
283    t = val;
284 #endif
285    eval_multiply(result, a, t);
286 }
287
288 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
289 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
290 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))
291 {
292    eval_multiply(result, result, val);
293 }
294
295 //
296 // Now over again for trivial cpp_int's:
297 //
298 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
299 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
300     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
301 eval_multiply(
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))
304 {
305    *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
306    result.sign(result.sign() != o.sign());
307    result.normalize();
308 }
309
310 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
311 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
312     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
313 eval_multiply(
314     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
315     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))
316 {
317    *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
318    result.normalize();
319 }
320
321 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
322 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
323     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
324 eval_multiply(
325     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
326     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
327     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))
328 {
329    *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
330    result.sign(a.sign() != b.sign());
331    result.normalize();
332 }
333
334 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
335 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
336     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
337 eval_multiply(
338     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
339     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
340     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))
341 {
342    *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
343    result.normalize();
344 }
345
346 //
347 // Special routines for multiplying two integers to obtain a multiprecision result:
348 //
349 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
350 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
351     !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
352 eval_multiply(
353     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
354     signed_double_limb_type a, signed_double_limb_type b)
355 {
356 #ifdef BOOST_NO_CXX14_CONSTEXPR
357    static const signed_double_limb_type mask      = ~static_cast<limb_type>(0);
358    static const unsigned                limb_bits = sizeof(limb_type) * CHAR_BIT;
359 #else
360    constexpr const signed_double_limb_type mask = ~static_cast<limb_type>(0);
361    constexpr const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
362 #endif
363    bool                                 s         = false;
364    if (a < 0)
365    {
366       a = -a;
367       s = true;
368    }
369    if (b < 0)
370    {
371       b = -b;
372       s = !s;
373    }
374    double_limb_type w = a & mask;
375    double_limb_type x = a >> limb_bits;
376    double_limb_type y = b & mask;
377    double_limb_type z = b >> limb_bits;
378
379    result.resize(4, 4);
380    limb_type* pr = result.limbs();
381
382    double_limb_type carry = w * y;
383 #ifdef __MSVC_RUNTIME_CHECKS
384    pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
385    carry >>= limb_bits;
386    carry += w * z + x * y;
387    pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
388    carry >>= limb_bits;
389    carry += x * z;
390    pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
391    pr[3] = static_cast<limb_type>(carry >> limb_bits);
392 #else
393    pr[0] = static_cast<limb_type>(carry);
394    carry >>= limb_bits;
395    carry += w * z + x * y;
396    pr[1] = static_cast<limb_type>(carry);
397    carry >>= limb_bits;
398    carry += x * z;
399    pr[2] = static_cast<limb_type>(carry);
400    pr[3] = static_cast<limb_type>(carry >> limb_bits);
401 #endif
402    result.sign(s);
403    result.normalize();
404 }
405
406 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
407 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
408     !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
409 eval_multiply(
410     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
411     double_limb_type a, double_limb_type b)
412 {
413 #ifdef BOOST_NO_CXX14_CONSTEXPR
414    static const signed_double_limb_type mask      = ~static_cast<limb_type>(0);
415    static const unsigned                limb_bits = sizeof(limb_type) * CHAR_BIT;
416 #else
417    constexpr const signed_double_limb_type mask = ~static_cast<limb_type>(0);
418    constexpr const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
419 #endif
420
421    double_limb_type w = a & mask;
422    double_limb_type x = a >> limb_bits;
423    double_limb_type y = b & mask;
424    double_limb_type z = b >> limb_bits;
425
426    result.resize(4, 4);
427    limb_type* pr = result.limbs();
428
429    double_limb_type carry = w * y;
430 #ifdef __MSVC_RUNTIME_CHECKS
431    pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
432    carry >>= limb_bits;
433    carry += w * z;
434    pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
435    carry >>= limb_bits;
436    pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
437    carry = x * y + pr[1];
438    pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
439    carry >>= limb_bits;
440    carry += pr[2] + x * z;
441    pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
442    pr[3] = static_cast<limb_type>(carry >> limb_bits);
443 #else
444    pr[0] = static_cast<limb_type>(carry);
445    carry >>= limb_bits;
446    carry += w * z;
447    pr[1] = static_cast<limb_type>(carry);
448    carry >>= limb_bits;
449    pr[2] = static_cast<limb_type>(carry);
450    carry = x * y + pr[1];
451    pr[1] = static_cast<limb_type>(carry);
452    carry >>= limb_bits;
453    carry += pr[2] + x * z;
454    pr[2] = static_cast<limb_type>(carry);
455    pr[3] = static_cast<limb_type>(carry >> limb_bits);
456 #endif
457    result.sign(false);
458    result.normalize();
459 }
460
461 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
462           unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
463 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
464     !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
465 eval_multiply(
466     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
467     cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
468     cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
469 {
470    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;
471    eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
472    result.sign(a.sign() != b.sign());
473 }
474
475 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
476 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_signed<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
477 eval_multiply(
478     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
479     SI a, SI b)
480 {
481    result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
482 }
483
484 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
485 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
486 eval_multiply(
487     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
488     UI a, UI b)
489 {
490    result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
491 }
492
493 #ifdef _MSC_VER
494 #pragma warning(pop)
495 #endif
496
497 }}} // namespace boost::multiprecision::backends
498
499 #endif