]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/multiprecision/cpp_int/multiply.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / 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 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
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 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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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