]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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); | |
b32b8144 | 51 | if(result.size() > i) |
7c673cae FG |
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 | ||
b32b8144 FG |
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) | |
7c673cae | 69 | { |
b32b8144 | 70 | if(result.size() < required) |
7c673cae FG |
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); | |
b32b8144 FG |
139 | unsigned j; |
140 | for(j = 0; j < inner_limit; ++j) | |
7c673cae FG |
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 | } | |
b32b8144 FG |
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 | } | |
7c673cae FG |
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 |