Chris@16
|
1 ///////////////////////////////////////////////////////////////
|
Chris@16
|
2 // Copyright 2012 John Maddock. Distributed under the Boost
|
Chris@16
|
3 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
Chris@16
|
5 //
|
Chris@16
|
6 // Comparison operators for cpp_int_backend:
|
Chris@16
|
7 //
|
Chris@16
|
8 #ifndef BOOST_MP_CPP_INT_MUL_HPP
|
Chris@16
|
9 #define BOOST_MP_CPP_INT_MUL_HPP
|
Chris@16
|
10
|
Chris@16
|
11 namespace boost{ namespace multiprecision{ namespace backends{
|
Chris@16
|
12
|
Chris@16
|
13 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>
|
Chris@16
|
14 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
|
Chris@16
|
15 eval_multiply(
|
Chris@16
|
16 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
17 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
Chris@16
|
18 const limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
19 {
|
Chris@16
|
20 if(!val)
|
Chris@16
|
21 {
|
Chris@16
|
22 result = static_cast<limb_type>(0);
|
Chris@16
|
23 return;
|
Chris@16
|
24 }
|
Chris@16
|
25 if((void*)&a != (void*)&result)
|
Chris@16
|
26 result.resize(a.size(), a.size());
|
Chris@16
|
27 double_limb_type carry = 0;
|
Chris@16
|
28 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
|
Chris@16
|
29 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
|
Chris@16
|
30 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
|
Chris@16
|
31 while(p != pe)
|
Chris@16
|
32 {
|
Chris@16
|
33 carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
|
Chris@16
|
34 *p = static_cast<limb_type>(carry);
|
Chris@16
|
35 carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
36 ++p, ++pa;
|
Chris@16
|
37 }
|
Chris@16
|
38 if(carry)
|
Chris@16
|
39 {
|
Chris@16
|
40 unsigned i = result.size();
|
Chris@16
|
41 result.resize(i + 1, i + 1);
|
Chris@16
|
42 if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (result.size() > i))
|
Chris@16
|
43 result.limbs()[i] = static_cast<limb_type>(carry);
|
Chris@16
|
44 }
|
Chris@16
|
45 result.sign(a.sign());
|
Chris@16
|
46 if(!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable)
|
Chris@16
|
47 result.normalize();
|
Chris@16
|
48 }
|
Chris@16
|
49
|
Chris@16
|
50 //
|
Chris@16
|
51 // resize_for_carry forces a resize of the underlying buffer only if a previous request
|
Chris@16
|
52 // for "required" elements could possibly have failed, *and* we have checking enabled.
|
Chris@16
|
53 // This will cause an overflow error inside resize():
|
Chris@16
|
54 //
|
Chris@16
|
55 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
56 inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/){}
|
Chris@16
|
57
|
Chris@16
|
58 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
59 inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, void>& result, unsigned required)
|
Chris@16
|
60 {
|
Chris@16
|
61 if(result.size() != required)
|
Chris@16
|
62 result.resize(required, required);
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 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>
|
Chris@16
|
66 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
|
Chris@16
|
67 eval_multiply(
|
Chris@16
|
68 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
69 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
Chris@16
|
70 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
71 {
|
Chris@16
|
72 // Very simple long multiplication, only usable for small numbers of limb_type's
|
Chris@16
|
73 // but that's the typical use case for this type anyway:
|
Chris@16
|
74 //
|
Chris@16
|
75 // Special cases first:
|
Chris@16
|
76 //
|
Chris@16
|
77 unsigned as = a.size();
|
Chris@16
|
78 unsigned bs = b.size();
|
Chris@16
|
79 typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
|
Chris@16
|
80 typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
|
Chris@16
|
81 if(as == 1)
|
Chris@16
|
82 {
|
Chris@16
|
83 bool s = b.sign() != a.sign();
|
Chris@16
|
84 if(bs == 1)
|
Chris@16
|
85 {
|
Chris@16
|
86 result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
|
Chris@16
|
87 }
|
Chris@16
|
88 else
|
Chris@16
|
89 {
|
Chris@16
|
90 limb_type l = *pa;
|
Chris@16
|
91 eval_multiply(result, b, l);
|
Chris@16
|
92 }
|
Chris@16
|
93 result.sign(s);
|
Chris@16
|
94 return;
|
Chris@16
|
95 }
|
Chris@16
|
96 if(bs == 1)
|
Chris@16
|
97 {
|
Chris@16
|
98 bool s = b.sign() != a.sign();
|
Chris@16
|
99 limb_type l = *pb;
|
Chris@16
|
100 eval_multiply(result, a, l);
|
Chris@16
|
101 result.sign(s);
|
Chris@16
|
102 return;
|
Chris@16
|
103 }
|
Chris@16
|
104
|
Chris@16
|
105 if((void*)&result == (void*)&a)
|
Chris@16
|
106 {
|
Chris@16
|
107 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
|
Chris@16
|
108 eval_multiply(result, t, b);
|
Chris@16
|
109 return;
|
Chris@16
|
110 }
|
Chris@16
|
111 if((void*)&result == (void*)&b)
|
Chris@16
|
112 {
|
Chris@16
|
113 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
|
Chris@16
|
114 eval_multiply(result, a, t);
|
Chris@16
|
115 return;
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 result.resize(as + bs, as + bs - 1);
|
Chris@16
|
119 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
|
Chris@16
|
120
|
Chris@16
|
121 static const double_limb_type limb_max = ~static_cast<limb_type>(0u);
|
Chris@16
|
122 static const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u);
|
Chris@16
|
123 BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max);
|
Chris@16
|
124
|
Chris@16
|
125 double_limb_type carry = 0;
|
Chris@16
|
126 std::memset(pr, 0, result.size() * sizeof(limb_type));
|
Chris@16
|
127 for(unsigned i = 0; i < as; ++i)
|
Chris@16
|
128 {
|
Chris@16
|
129 unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
|
Chris@16
|
130 for(unsigned j = 0; j < inner_limit; ++j)
|
Chris@16
|
131 {
|
Chris@16
|
132 BOOST_ASSERT(i+j < result.size());
|
Chris@16
|
133 BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized
|
Chris@16
|
134 || ((std::numeric_limits<double_limb_type>::max)() - carry
|
Chris@16
|
135 >
|
Chris@16
|
136 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)));
|
Chris@16
|
137 carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
|
Chris@16
|
138 BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j]));
|
Chris@16
|
139 carry += pr[i + j];
|
Chris@16
|
140 pr[i + j] = static_cast<limb_type>(carry);
|
Chris@16
|
141 carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
142 BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
|
Chris@16
|
143 }
|
Chris@16
|
144 resize_for_carry(result, as + bs); // May throw if checking is enabled
|
Chris@16
|
145 if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (i + bs < result.size()))
|
Chris@16
|
146 pr[i + bs] = static_cast<limb_type>(carry);
|
Chris@16
|
147 carry = 0;
|
Chris@16
|
148 }
|
Chris@16
|
149 result.normalize();
|
Chris@16
|
150 //
|
Chris@16
|
151 // Set the sign of the result:
|
Chris@16
|
152 //
|
Chris@16
|
153 result.sign(a.sign() != b.sign());
|
Chris@16
|
154 }
|
Chris@16
|
155
|
Chris@16
|
156 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>
|
Chris@16
|
157 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
|
Chris@16
|
158 eval_multiply(
|
Chris@16
|
159 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
160 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
161 {
|
Chris@16
|
162 eval_multiply(result, result, a);
|
Chris@16
|
163 }
|
Chris@16
|
164
|
Chris@16
|
165 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
166 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
167 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
168 {
|
Chris@16
|
169 eval_multiply(result, result, val);
|
Chris@16
|
170 }
|
Chris@16
|
171
|
Chris@16
|
172 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>
|
Chris@16
|
173 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
|
Chris@16
|
174 eval_multiply(
|
Chris@16
|
175 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
176 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
Chris@16
|
177 const double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
178 {
|
Chris@16
|
179 if(val <= (std::numeric_limits<limb_type>::max)())
|
Chris@16
|
180 {
|
Chris@16
|
181 eval_multiply(result, a, static_cast<limb_type>(val));
|
Chris@16
|
182 }
|
Chris@16
|
183 else
|
Chris@16
|
184 {
|
Chris@16
|
185 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
|
Chris@16
|
186 eval_multiply(result, a, t);
|
Chris@16
|
187 }
|
Chris@16
|
188 }
|
Chris@16
|
189
|
Chris@16
|
190 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
191 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
192 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
193 {
|
Chris@16
|
194 eval_multiply(result, result, val);
|
Chris@16
|
195 }
|
Chris@16
|
196
|
Chris@16
|
197 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>
|
Chris@16
|
198 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
|
Chris@16
|
199 eval_multiply(
|
Chris@16
|
200 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
201 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
Chris@16
|
202 const signed_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
203 {
|
Chris@16
|
204 if(val > 0)
|
Chris@16
|
205 eval_multiply(result, a, static_cast<limb_type>(val));
|
Chris@16
|
206 else
|
Chris@16
|
207 {
|
Chris@101
|
208 eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
|
Chris@16
|
209 result.negate();
|
Chris@16
|
210 }
|
Chris@16
|
211 }
|
Chris@16
|
212
|
Chris@16
|
213 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
214 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
215 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
216 {
|
Chris@16
|
217 eval_multiply(result, result, val);
|
Chris@16
|
218 }
|
Chris@16
|
219
|
Chris@16
|
220 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>
|
Chris@16
|
221 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
|
Chris@16
|
222 eval_multiply(
|
Chris@16
|
223 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
224 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
Chris@16
|
225 const signed_double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
226 {
|
Chris@16
|
227 if(val > 0)
|
Chris@16
|
228 {
|
Chris@16
|
229 if(val <= (std::numeric_limits<limb_type>::max)())
|
Chris@16
|
230 {
|
Chris@16
|
231 eval_multiply(result, a, static_cast<limb_type>(val));
|
Chris@16
|
232 return;
|
Chris@16
|
233 }
|
Chris@16
|
234 }
|
Chris@16
|
235 else if(val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
|
Chris@16
|
236 {
|
Chris@101
|
237 eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
|
Chris@16
|
238 result.negate();
|
Chris@16
|
239 return;
|
Chris@16
|
240 }
|
Chris@16
|
241 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
|
Chris@16
|
242 eval_multiply(result, a, t);
|
Chris@16
|
243 }
|
Chris@16
|
244
|
Chris@16
|
245 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
246 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
247 eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_double_limb_type& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
248 {
|
Chris@16
|
249 eval_multiply(result, result, val);
|
Chris@16
|
250 }
|
Chris@16
|
251
|
Chris@16
|
252 //
|
Chris@16
|
253 // Now over again for trivial cpp_int's:
|
Chris@16
|
254 //
|
Chris@16
|
255 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
256 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
257 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
258 && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
259 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
260 || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
Chris@16
|
261 >::type
|
Chris@16
|
262 eval_multiply(
|
Chris@16
|
263 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
264 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
265 {
|
Chris@16
|
266 *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
Chris@16
|
267 result.sign(result.sign() != o.sign());
|
Chris@16
|
268 result.normalize();
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
272 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
273 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
274 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
275 >::type
|
Chris@16
|
276 eval_multiply(
|
Chris@16
|
277 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
278 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
279 {
|
Chris@16
|
280 *result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
Chris@16
|
281 result.normalize();
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
285 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
286 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
287 && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
288 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
289 || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
Chris@16
|
290 >::type
|
Chris@16
|
291 eval_multiply(
|
Chris@16
|
292 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
293 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
Chris@16
|
294 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
295 {
|
Chris@16
|
296 *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
Chris@16
|
297 result.sign(a.sign() != b.sign());
|
Chris@16
|
298 result.normalize();
|
Chris@16
|
299 }
|
Chris@16
|
300
|
Chris@16
|
301 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
302 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
303 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
304 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
305 >::type
|
Chris@16
|
306 eval_multiply(
|
Chris@16
|
307 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
308 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
Chris@16
|
309 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
310 {
|
Chris@16
|
311 *result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
Chris@16
|
312 result.normalize();
|
Chris@16
|
313 }
|
Chris@16
|
314
|
Chris@16
|
315 //
|
Chris@16
|
316 // Special routines for multiplying two integers to obtain a multiprecision result:
|
Chris@16
|
317 //
|
Chris@16
|
318 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
319 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
320 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
321 >::type
|
Chris@16
|
322 eval_multiply(
|
Chris@16
|
323 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
324 signed_double_limb_type a, signed_double_limb_type b)
|
Chris@16
|
325 {
|
Chris@16
|
326 static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
|
Chris@16
|
327 static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
Chris@16
|
328 bool s = false;
|
Chris@16
|
329 double_limb_type w, x, y, z;
|
Chris@16
|
330 if(a < 0)
|
Chris@16
|
331 {
|
Chris@16
|
332 a = -a;
|
Chris@16
|
333 s = true;
|
Chris@16
|
334 }
|
Chris@16
|
335 if(b < 0)
|
Chris@16
|
336 {
|
Chris@16
|
337 b = -b;
|
Chris@16
|
338 s = !s;
|
Chris@16
|
339 }
|
Chris@16
|
340 w = a & mask;
|
Chris@16
|
341 x = a >> limb_bits;
|
Chris@16
|
342 y = b & mask;
|
Chris@16
|
343 z = b >> limb_bits;
|
Chris@16
|
344
|
Chris@16
|
345 result.resize(4, 4);
|
Chris@16
|
346 limb_type* pr = result.limbs();
|
Chris@16
|
347
|
Chris@16
|
348 double_limb_type carry = w * y;
|
Chris@16
|
349 pr[0] = static_cast<limb_type>(carry);
|
Chris@16
|
350 carry >>= limb_bits;
|
Chris@16
|
351 carry += w * z + x * y;
|
Chris@16
|
352 pr[1] = static_cast<limb_type>(carry);
|
Chris@16
|
353 carry >>= limb_bits;
|
Chris@16
|
354 carry += x * z;
|
Chris@16
|
355 pr[2] = static_cast<limb_type>(carry);
|
Chris@16
|
356 pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
Chris@16
|
357
|
Chris@16
|
358 result.sign(s);
|
Chris@16
|
359 result.normalize();
|
Chris@16
|
360 }
|
Chris@16
|
361
|
Chris@16
|
362 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
363 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
364 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
365 >::type
|
Chris@16
|
366 eval_multiply(
|
Chris@16
|
367 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
368 double_limb_type a, double_limb_type b)
|
Chris@16
|
369 {
|
Chris@16
|
370 static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
|
Chris@16
|
371 static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
Chris@16
|
372
|
Chris@16
|
373 double_limb_type w, x, y, z;
|
Chris@16
|
374 w = a & mask;
|
Chris@16
|
375 x = a >> limb_bits;
|
Chris@16
|
376 y = b & mask;
|
Chris@16
|
377 z = b >> limb_bits;
|
Chris@16
|
378
|
Chris@16
|
379 result.resize(4, 4);
|
Chris@16
|
380 limb_type* pr = result.limbs();
|
Chris@16
|
381
|
Chris@16
|
382 double_limb_type carry = w * y;
|
Chris@16
|
383 pr[0] = static_cast<limb_type>(carry);
|
Chris@16
|
384 carry >>= limb_bits;
|
Chris@16
|
385 carry += w * z;
|
Chris@16
|
386 pr[1] = static_cast<limb_type>(carry);
|
Chris@16
|
387 carry >>= limb_bits;
|
Chris@16
|
388 pr[2] = static_cast<limb_type>(carry);
|
Chris@16
|
389 carry = x * y + pr[1];
|
Chris@16
|
390 pr[1] = static_cast<limb_type>(carry);
|
Chris@16
|
391 carry >>= limb_bits;
|
Chris@16
|
392 carry += pr[2] + x * z;
|
Chris@16
|
393 pr[2] = static_cast<limb_type>(carry);
|
Chris@16
|
394 pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
Chris@16
|
395
|
Chris@16
|
396 result.sign(false);
|
Chris@16
|
397 result.normalize();
|
Chris@16
|
398 }
|
Chris@16
|
399
|
Chris@16
|
400 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
|
Chris@16
|
401 unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
Chris@16
|
402 BOOST_MP_FORCEINLINE typename enable_if_c<
|
Chris@16
|
403 !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
404 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
Chris@16
|
405 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
Chris@16
|
406 >::type
|
Chris@16
|
407 eval_multiply(
|
Chris@16
|
408 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
409 cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
|
Chris@16
|
410 cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
|
Chris@16
|
411 {
|
Chris@16
|
412 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;
|
Chris@16
|
413 eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
|
Chris@16
|
414 result.sign(a.sign() != b.sign());
|
Chris@16
|
415 }
|
Chris@16
|
416
|
Chris@16
|
417 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
|
Chris@16
|
418 BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
|
Chris@16
|
419 eval_multiply(
|
Chris@16
|
420 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
421 SI a, SI b)
|
Chris@16
|
422 {
|
Chris@16
|
423 result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
|
Chris@16
|
424 }
|
Chris@16
|
425
|
Chris@16
|
426 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
|
Chris@16
|
427 BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
|
Chris@16
|
428 eval_multiply(
|
Chris@16
|
429 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
430 UI a, UI b)
|
Chris@16
|
431 {
|
Chris@16
|
432 result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
|
Chris@16
|
433 }
|
Chris@16
|
434
|
Chris@16
|
435 }}} // namespaces
|
Chris@16
|
436
|
Chris@16
|
437 #endif
|