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_
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 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)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>
resize_for_carry(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> &,unsigned)65 inline 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>
resize_for_carry(cpp_int_backend<MinBits1,MaxBits1,SignType1,checked,Allocator1> & result,unsigned required)68 inline 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 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)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 
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);
133 
134    double_limb_type carry = 0;
135    std::memset(pr, 0, result.size() * sizeof(limb_type));
136    for(unsigned i = 0; i < as; ++i)
137    {
138       unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
139       unsigned j;
140       for(j = 0; j < inner_limit; ++j)
141       {
142          BOOST_ASSERT(i+j < result.size());
143 #if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
144          BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized
145             || ((std::numeric_limits<double_limb_type>::max)() - carry
146                   >
147                 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 #endif
149          carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
150          BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j]));
151          carry += pr[i + j];
152 #ifdef __MSVC_RUNTIME_CHECKS
153          pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
154 #else
155          pr[i + j] = static_cast<limb_type>(carry);
156 #endif
157          carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
158          BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
159       }
160       if(carry)
161       {
162          resize_for_carry(result, i + j + 1);  // May throw if checking is enabled
163          if(i + j < result.size())
164 #ifdef __MSVC_RUNTIME_CHECKS
165             pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
166 #else
167             pr[i + j] = static_cast<limb_type>(carry);
168 #endif
169       }
170       carry = 0;
171    }
172    result.normalize();
173    //
174    // Set the sign of the result:
175    //
176    result.sign(a.sign() != b.sign());
177 }
178 
179 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>
180 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)181    eval_multiply(
182       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
183       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))
184 {
185     eval_multiply(result, result, a);
186 }
187 
188 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
189 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)190    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))
191 {
192    eval_multiply(result, result, val);
193 }
194 
195 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>
196 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)197    eval_multiply(
198       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
199       const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
200       const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
201 {
202    if(val <= (std::numeric_limits<limb_type>::max)())
203    {
204       eval_multiply(result, a, static_cast<limb_type>(val));
205    }
206    else
207    {
208 #if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
209       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
210 #else
211       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
212       t = val;
213 #endif
214       eval_multiply(result, a, t);
215    }
216 }
217 
218 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
219 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)220    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))
221 {
222    eval_multiply(result, result, val);
223 }
224 
225 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>
226 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)227    eval_multiply(
228       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
229       const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
230       const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
231 {
232    if(val > 0)
233       eval_multiply(result, a, static_cast<limb_type>(val));
234    else
235    {
236       eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
237       result.negate();
238    }
239 }
240 
241 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
242 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)243    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))
244 {
245    eval_multiply(result, result, val);
246 }
247 
248 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>
249 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)250    eval_multiply(
251       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
252       const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
253       const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
254 {
255    if(val > 0)
256    {
257       if(val <= (std::numeric_limits<limb_type>::max)())
258       {
259          eval_multiply(result, a, static_cast<limb_type>(val));
260          return;
261       }
262    }
263    else if(val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
264    {
265       eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
266       result.negate();
267       return;
268    }
269 #if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
270    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
271 #else
272    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
273    t = val;
274 #endif
275    eval_multiply(result, a, t);
276 }
277 
278 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
279 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)280    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))
281 {
282    eval_multiply(result, result, val);
283 }
284 
285 //
286 // Now over again for trivial cpp_int's:
287 //
288 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
289 BOOST_MP_FORCEINLINE typename enable_if_c<
290          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
291          && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
292          && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
293             || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
294          >::type
eval_multiply(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)295    eval_multiply(
296       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
297       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))
298 {
299    *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
300    result.sign(result.sign() != o.sign());
301    result.normalize();
302 }
303 
304 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
305 BOOST_MP_FORCEINLINE typename enable_if_c<
306          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
307          && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
308          >::type
eval_multiply(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)309    eval_multiply(
310       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
311       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))
312 {
313    *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
314    result.normalize();
315 }
316 
317 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
318 BOOST_MP_FORCEINLINE typename enable_if_c<
319          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
320          && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
321          && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
322             || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
323          >::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)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 typename enable_if_c<
336          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
337          && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
338          >::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)339    eval_multiply(
340       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
341       const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
342       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))
343 {
344    *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
345    result.normalize();
346 }
347 
348 //
349 // Special routines for multiplying two integers to obtain a multiprecision result:
350 //
351 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
352 BOOST_MP_FORCEINLINE typename enable_if_c<
353             !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
354          >::type
eval_multiply(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,signed_double_limb_type a,signed_double_limb_type b)355    eval_multiply(
356       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
357       signed_double_limb_type a, signed_double_limb_type b)
358 {
359    static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
360    static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
361    bool s = false;
362    double_limb_type w, x, y, z;
363    if(a < 0)
364    {
365       a = -a;
366       s = true;
367    }
368    if(b < 0)
369    {
370       b = -b;
371       s = !s;
372    }
373    w = a & mask;
374    x = a >> limb_bits;
375    y = b & mask;
376    z = b >> limb_bits;
377 
378    result.resize(4, 4);
379    limb_type* pr = result.limbs();
380 
381    double_limb_type carry = w * y;
382 #ifdef __MSVC_RUNTIME_CHECKS
383    pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
384    carry >>= limb_bits;
385    carry += w * z + x * y;
386    pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
387    carry >>= limb_bits;
388    carry += x * z;
389    pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
390    pr[3] = static_cast<limb_type>(carry >> limb_bits);
391 #else
392    pr[0] = static_cast<limb_type>(carry);
393    carry >>= limb_bits;
394    carry += w * z + x * y;
395    pr[1] = static_cast<limb_type>(carry);
396    carry >>= limb_bits;
397    carry += x * z;
398    pr[2] = static_cast<limb_type>(carry);
399    pr[3] = static_cast<limb_type>(carry >> limb_bits);
400 #endif
401    result.sign(s);
402    result.normalize();
403 }
404 
405 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
406 BOOST_MP_FORCEINLINE typename enable_if_c<
407             !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
408          >::type
eval_multiply(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,double_limb_type a,double_limb_type b)409    eval_multiply(
410       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
411       double_limb_type a, double_limb_type b)
412 {
413    static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
414    static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
415 
416    double_limb_type w, x, y, z;
417    w = a & mask;
418    x = a >> limb_bits;
419    y = b & mask;
420    z = b >> limb_bits;
421 
422    result.resize(4, 4);
423    limb_type* pr = result.limbs();
424 
425    double_limb_type carry = w * y;
426 #ifdef __MSVC_RUNTIME_CHECKS
427    pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
428    carry >>= limb_bits;
429    carry += w * z;
430    pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
431    carry >>= limb_bits;
432    pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
433    carry = x * y + pr[1];
434    pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
435    carry >>= limb_bits;
436    carry += pr[2] + x * z;
437    pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
438    pr[3] = static_cast<limb_type>(carry >> limb_bits);
439 #else
440    pr[0] = static_cast<limb_type>(carry);
441    carry >>= limb_bits;
442    carry += w * z;
443    pr[1] = static_cast<limb_type>(carry);
444    carry >>= limb_bits;
445    pr[2] = static_cast<limb_type>(carry);
446    carry = x * y + pr[1];
447    pr[1] = static_cast<limb_type>(carry);
448    carry >>= limb_bits;
449    carry += pr[2] + x * z;
450    pr[2] = static_cast<limb_type>(carry);
451    pr[3] = static_cast<limb_type>(carry >> limb_bits);
452 #endif
453    result.sign(false);
454    result.normalize();
455 }
456 
457 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
458           unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
459 BOOST_MP_FORCEINLINE typename enable_if_c<
460             !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
461             && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
462             && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
463          >::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)464    eval_multiply(
465       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
466       cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
467       cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
468 {
469    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;
470    eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
471    result.sign(a.sign() != b.sign());
472 }
473 
474 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
475 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)476    eval_multiply(
477       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
478       SI a, SI b)
479 {
480    result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
481 }
482 
483 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
484 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)485    eval_multiply(
486       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
487       UI a, UI b)
488 {
489    result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
490 }
491 
492 #ifdef _MSC_VER
493 #pragma warning(pop)
494 #endif
495 
496 }}} // namespaces
497 
498 #endif
499