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 #ifndef BOOST_MP_INT_FUNC_HPP
|
Chris@16
|
7 #define BOOST_MP_INT_FUNC_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #include <boost/multiprecision/number.hpp>
|
Chris@16
|
10
|
Chris@16
|
11 namespace boost{ namespace multiprecision{
|
Chris@16
|
12
|
Chris@16
|
13 namespace default_ops
|
Chris@16
|
14 {
|
Chris@16
|
15
|
Chris@16
|
16 template <class Backend>
|
Chris@16
|
17 inline void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r)
|
Chris@16
|
18 {
|
Chris@16
|
19 eval_divide(q, x, y);
|
Chris@16
|
20 eval_modulus(r, x, y);
|
Chris@16
|
21 }
|
Chris@16
|
22
|
Chris@16
|
23 template <class Backend, class Integer>
|
Chris@16
|
24 inline Integer eval_integer_modulus(const Backend& x, Integer val)
|
Chris@16
|
25 {
|
Chris@16
|
26 BOOST_MP_USING_ABS
|
Chris@16
|
27 using default_ops::eval_modulus;
|
Chris@16
|
28 using default_ops::eval_convert_to;
|
Chris@16
|
29 typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type int_type;
|
Chris@16
|
30 Backend t;
|
Chris@16
|
31 eval_modulus(t, x, static_cast<int_type>(val));
|
Chris@16
|
32 Integer result;
|
Chris@16
|
33 eval_convert_to(&result, t);
|
Chris@16
|
34 return abs(result);
|
Chris@16
|
35 }
|
Chris@16
|
36
|
Chris@16
|
37 #ifdef BOOST_MSVC
|
Chris@16
|
38 #pragma warning(push)
|
Chris@16
|
39 #pragma warning(disable:4127)
|
Chris@16
|
40 #endif
|
Chris@16
|
41
|
Chris@16
|
42 template <class B>
|
Chris@16
|
43 inline void eval_gcd(B& result, const B& a, const B& b)
|
Chris@16
|
44 {
|
Chris@16
|
45 using default_ops::eval_lsb;
|
Chris@16
|
46 using default_ops::eval_is_zero;
|
Chris@16
|
47 using default_ops::eval_get_sign;
|
Chris@16
|
48
|
Chris@16
|
49 int shift;
|
Chris@16
|
50
|
Chris@16
|
51 B u(a), v(b);
|
Chris@16
|
52
|
Chris@16
|
53 int s = eval_get_sign(u);
|
Chris@16
|
54
|
Chris@16
|
55 /* GCD(0,x) := x */
|
Chris@16
|
56 if(s < 0)
|
Chris@16
|
57 {
|
Chris@16
|
58 u.negate();
|
Chris@16
|
59 }
|
Chris@16
|
60 else if(s == 0)
|
Chris@16
|
61 {
|
Chris@16
|
62 result = v;
|
Chris@16
|
63 return;
|
Chris@16
|
64 }
|
Chris@16
|
65 s = eval_get_sign(v);
|
Chris@16
|
66 if(s < 0)
|
Chris@16
|
67 {
|
Chris@16
|
68 v.negate();
|
Chris@16
|
69 }
|
Chris@16
|
70 else if(s == 0)
|
Chris@16
|
71 {
|
Chris@16
|
72 result = u;
|
Chris@16
|
73 return;
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@16
|
76 /* Let shift := lg K, where K is the greatest power of 2
|
Chris@16
|
77 dividing both u and v. */
|
Chris@16
|
78
|
Chris@16
|
79 unsigned us = eval_lsb(u);
|
Chris@16
|
80 unsigned vs = eval_lsb(v);
|
Chris@16
|
81 shift = (std::min)(us, vs);
|
Chris@16
|
82 eval_right_shift(u, us);
|
Chris@16
|
83 eval_right_shift(v, vs);
|
Chris@16
|
84
|
Chris@16
|
85 do
|
Chris@16
|
86 {
|
Chris@16
|
87 /* Now u and v are both odd, so diff(u, v) is even.
|
Chris@16
|
88 Let u = min(u, v), v = diff(u, v)/2. */
|
Chris@16
|
89 s = u.compare(v);
|
Chris@16
|
90 if(s > 0)
|
Chris@16
|
91 u.swap(v);
|
Chris@16
|
92 if(s == 0)
|
Chris@16
|
93 break;
|
Chris@16
|
94 eval_subtract(v, u);
|
Chris@16
|
95 vs = eval_lsb(v);
|
Chris@16
|
96 eval_right_shift(v, vs);
|
Chris@16
|
97 }
|
Chris@16
|
98 while(true);
|
Chris@16
|
99
|
Chris@16
|
100 result = u;
|
Chris@16
|
101 eval_left_shift(result, shift);
|
Chris@16
|
102 }
|
Chris@16
|
103
|
Chris@16
|
104 #ifdef BOOST_MSVC
|
Chris@16
|
105 #pragma warning(pop)
|
Chris@16
|
106 #endif
|
Chris@16
|
107
|
Chris@16
|
108 template <class B>
|
Chris@16
|
109 inline void eval_lcm(B& result, const B& a, const B& b)
|
Chris@16
|
110 {
|
Chris@16
|
111 typedef typename mpl::front<typename B::unsigned_types>::type ui_type;
|
Chris@16
|
112 B t;
|
Chris@16
|
113 eval_gcd(t, a, b);
|
Chris@16
|
114
|
Chris@16
|
115 if(eval_is_zero(t))
|
Chris@16
|
116 {
|
Chris@16
|
117 result = static_cast<ui_type>(0);
|
Chris@16
|
118 }
|
Chris@16
|
119 else
|
Chris@16
|
120 {
|
Chris@16
|
121 eval_divide(result, a, t);
|
Chris@16
|
122 eval_multiply(result, b);
|
Chris@16
|
123 }
|
Chris@16
|
124 if(eval_get_sign(result) < 0)
|
Chris@16
|
125 result.negate();
|
Chris@16
|
126 }
|
Chris@16
|
127
|
Chris@16
|
128 }
|
Chris@16
|
129
|
Chris@16
|
130 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
131 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
Chris@16
|
132 divide_qr(const number<Backend, ExpressionTemplates>& x, const number<Backend, ExpressionTemplates>& y,
|
Chris@16
|
133 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
Chris@16
|
134 {
|
Chris@16
|
135 using default_ops::eval_qr;
|
Chris@16
|
136 eval_qr(x.backend(), y.backend(), q.backend(), r.backend());
|
Chris@16
|
137 }
|
Chris@16
|
138
|
Chris@16
|
139 template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
|
Chris@16
|
140 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
Chris@16
|
141 divide_qr(const number<Backend, ExpressionTemplates>& x, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& y,
|
Chris@16
|
142 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
Chris@16
|
143 {
|
Chris@16
|
144 divide_qr(x, number<Backend, ExpressionTemplates>(y), q, r);
|
Chris@16
|
145 }
|
Chris@16
|
146
|
Chris@16
|
147 template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
148 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
Chris@16
|
149 divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const number<Backend, ExpressionTemplates>& y,
|
Chris@16
|
150 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
Chris@16
|
151 {
|
Chris@16
|
152 divide_qr(number<Backend, ExpressionTemplates>(x), y, q, r);
|
Chris@16
|
153 }
|
Chris@16
|
154
|
Chris@16
|
155 template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b, class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
156 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
Chris@16
|
157 divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& y,
|
Chris@16
|
158 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
Chris@16
|
159 {
|
Chris@16
|
160 divide_qr(number<Backend, ExpressionTemplates>(x), number<Backend, ExpressionTemplates>(y), q, r);
|
Chris@16
|
161 }
|
Chris@16
|
162
|
Chris@16
|
163 template <class Backend, expression_template_option ExpressionTemplates, class Integer>
|
Chris@16
|
164 inline typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<Backend>::value == number_kind_integer> >, Integer>::type
|
Chris@16
|
165 integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
|
Chris@16
|
166 {
|
Chris@16
|
167 using default_ops::eval_integer_modulus;
|
Chris@16
|
168 return eval_integer_modulus(x.backend(), val);
|
Chris@16
|
169 }
|
Chris@16
|
170
|
Chris@16
|
171 template <class tag, class A1, class A2, class A3, class A4, class Integer>
|
Chris@16
|
172 inline typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer> >, Integer>::type
|
Chris@16
|
173 integer_modulus(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, Integer val)
|
Chris@16
|
174 {
|
Chris@16
|
175 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type result_type;
|
Chris@16
|
176 return integer_modulus(result_type(x), val);
|
Chris@16
|
177 }
|
Chris@16
|
178
|
Chris@16
|
179 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
180 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
|
Chris@16
|
181 lsb(const number<Backend, ExpressionTemplates>& x)
|
Chris@16
|
182 {
|
Chris@16
|
183 using default_ops::eval_lsb;
|
Chris@16
|
184 return eval_lsb(x.backend());
|
Chris@16
|
185 }
|
Chris@16
|
186
|
Chris@16
|
187 template <class tag, class A1, class A2, class A3, class A4>
|
Chris@16
|
188 inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
|
Chris@16
|
189 lsb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
|
Chris@16
|
190 {
|
Chris@16
|
191 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
Chris@16
|
192 number_type n(x);
|
Chris@16
|
193 using default_ops::eval_lsb;
|
Chris@16
|
194 return eval_lsb(n.backend());
|
Chris@16
|
195 }
|
Chris@16
|
196
|
Chris@16
|
197 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
198 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
|
Chris@16
|
199 msb(const number<Backend, ExpressionTemplates>& x)
|
Chris@16
|
200 {
|
Chris@16
|
201 using default_ops::eval_msb;
|
Chris@16
|
202 return eval_msb(x.backend());
|
Chris@16
|
203 }
|
Chris@16
|
204
|
Chris@16
|
205 template <class tag, class A1, class A2, class A3, class A4>
|
Chris@16
|
206 inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
|
Chris@16
|
207 msb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
|
Chris@16
|
208 {
|
Chris@16
|
209 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
Chris@16
|
210 number_type n(x);
|
Chris@16
|
211 using default_ops::eval_msb;
|
Chris@16
|
212 return eval_msb(n.backend());
|
Chris@16
|
213 }
|
Chris@16
|
214
|
Chris@16
|
215 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
216 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, bool>::type
|
Chris@16
|
217 bit_test(const number<Backend, ExpressionTemplates>& x, unsigned index)
|
Chris@16
|
218 {
|
Chris@16
|
219 using default_ops::eval_bit_test;
|
Chris@16
|
220 return eval_bit_test(x.backend(), index);
|
Chris@16
|
221 }
|
Chris@16
|
222
|
Chris@16
|
223 template <class tag, class A1, class A2, class A3, class A4>
|
Chris@16
|
224 inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, bool>::type
|
Chris@16
|
225 bit_test(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, unsigned index)
|
Chris@16
|
226 {
|
Chris@16
|
227 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
Chris@16
|
228 number_type n(x);
|
Chris@16
|
229 using default_ops::eval_bit_test;
|
Chris@16
|
230 return eval_bit_test(n.backend(), index);
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
234 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
Chris@16
|
235 bit_set(number<Backend, ExpressionTemplates>& x, unsigned index)
|
Chris@16
|
236 {
|
Chris@16
|
237 using default_ops::eval_bit_set;
|
Chris@16
|
238 eval_bit_set(x.backend(), index);
|
Chris@16
|
239 return x;
|
Chris@16
|
240 }
|
Chris@16
|
241
|
Chris@16
|
242 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
243 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
Chris@16
|
244 bit_unset(number<Backend, ExpressionTemplates>& x, unsigned index)
|
Chris@16
|
245 {
|
Chris@16
|
246 using default_ops::eval_bit_unset;
|
Chris@16
|
247 eval_bit_unset(x.backend(), index);
|
Chris@16
|
248 return x;
|
Chris@16
|
249 }
|
Chris@16
|
250
|
Chris@16
|
251 template <class Backend, expression_template_option ExpressionTemplates>
|
Chris@16
|
252 inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
Chris@16
|
253 bit_flip(number<Backend, ExpressionTemplates>& x, unsigned index)
|
Chris@16
|
254 {
|
Chris@16
|
255 using default_ops::eval_bit_flip;
|
Chris@16
|
256 eval_bit_flip(x.backend(), index);
|
Chris@16
|
257 return x;
|
Chris@16
|
258 }
|
Chris@16
|
259
|
Chris@16
|
260 namespace default_ops{
|
Chris@16
|
261
|
Chris@16
|
262 //
|
Chris@16
|
263 // Within powm, we need a type with twice as many digits as the argument type, define
|
Chris@16
|
264 // a traits class to obtain that type:
|
Chris@16
|
265 //
|
Chris@16
|
266 template <class Backend>
|
Chris@16
|
267 struct double_precision_type
|
Chris@16
|
268 {
|
Chris@16
|
269 typedef Backend type;
|
Chris@16
|
270 };
|
Chris@16
|
271
|
Chris@16
|
272 //
|
Chris@101
|
273 // If the exponent is a signed integer type, then we need to
|
Chris@101
|
274 // check the value is positive:
|
Chris@101
|
275 //
|
Chris@101
|
276 template <class Backend>
|
Chris@101
|
277 inline void check_sign_of_backend(const Backend& v, const mpl::true_)
|
Chris@101
|
278 {
|
Chris@101
|
279 if(eval_get_sign(v) < 0)
|
Chris@101
|
280 {
|
Chris@101
|
281 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
Chris@101
|
282 }
|
Chris@101
|
283 }
|
Chris@101
|
284 template <class Backend>
|
Chris@101
|
285 inline void check_sign_of_backend(const Backend&, const mpl::false_){}
|
Chris@101
|
286 //
|
Chris@16
|
287 // Calculate (a^p)%c:
|
Chris@16
|
288 //
|
Chris@16
|
289 template <class Backend>
|
Chris@16
|
290 void eval_powm(Backend& result, const Backend& a, const Backend& p, const Backend& c)
|
Chris@16
|
291 {
|
Chris@16
|
292 using default_ops::eval_bit_test;
|
Chris@16
|
293 using default_ops::eval_get_sign;
|
Chris@16
|
294 using default_ops::eval_multiply;
|
Chris@16
|
295 using default_ops::eval_modulus;
|
Chris@16
|
296 using default_ops::eval_right_shift;
|
Chris@16
|
297
|
Chris@16
|
298 typedef typename double_precision_type<Backend>::type double_type;
|
Chris@16
|
299 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
Chris@101
|
300
|
Chris@101
|
301 check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
|
Chris@16
|
302
|
Chris@16
|
303 double_type x, y(a), b(p), t;
|
Chris@16
|
304 x = ui_type(1u);
|
Chris@16
|
305
|
Chris@16
|
306 while(eval_get_sign(b) > 0)
|
Chris@16
|
307 {
|
Chris@16
|
308 if(eval_bit_test(b, 0))
|
Chris@16
|
309 {
|
Chris@16
|
310 eval_multiply(t, x, y);
|
Chris@16
|
311 eval_modulus(x, t, c);
|
Chris@16
|
312 }
|
Chris@16
|
313 eval_multiply(t, y, y);
|
Chris@16
|
314 eval_modulus(y, t, c);
|
Chris@16
|
315 eval_right_shift(b, ui_type(1));
|
Chris@16
|
316 }
|
Chris@16
|
317 Backend x2(x);
|
Chris@16
|
318 eval_modulus(result, x2, c);
|
Chris@16
|
319 }
|
Chris@16
|
320
|
Chris@16
|
321 template <class Backend, class Integer>
|
Chris@16
|
322 void eval_powm(Backend& result, const Backend& a, const Backend& p, Integer c)
|
Chris@16
|
323 {
|
Chris@16
|
324 typedef typename double_precision_type<Backend>::type double_type;
|
Chris@16
|
325 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
Chris@16
|
326 typedef typename boost::multiprecision::detail::canonical<Integer, double_type>::type i1_type;
|
Chris@16
|
327 typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type i2_type;
|
Chris@16
|
328
|
Chris@16
|
329 using default_ops::eval_bit_test;
|
Chris@16
|
330 using default_ops::eval_get_sign;
|
Chris@16
|
331 using default_ops::eval_multiply;
|
Chris@16
|
332 using default_ops::eval_modulus;
|
Chris@16
|
333 using default_ops::eval_right_shift;
|
Chris@16
|
334
|
Chris@101
|
335 check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
|
Chris@101
|
336
|
Chris@16
|
337 if(eval_get_sign(p) < 0)
|
Chris@16
|
338 {
|
Chris@16
|
339 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
Chris@16
|
340 }
|
Chris@16
|
341
|
Chris@16
|
342 double_type x, y(a), b(p), t;
|
Chris@16
|
343 x = ui_type(1u);
|
Chris@16
|
344
|
Chris@16
|
345 while(eval_get_sign(b) > 0)
|
Chris@16
|
346 {
|
Chris@16
|
347 if(eval_bit_test(b, 0))
|
Chris@16
|
348 {
|
Chris@16
|
349 eval_multiply(t, x, y);
|
Chris@16
|
350 eval_modulus(x, t, static_cast<i1_type>(c));
|
Chris@16
|
351 }
|
Chris@16
|
352 eval_multiply(t, y, y);
|
Chris@16
|
353 eval_modulus(y, t, static_cast<i1_type>(c));
|
Chris@16
|
354 eval_right_shift(b, ui_type(1));
|
Chris@16
|
355 }
|
Chris@16
|
356 Backend x2(x);
|
Chris@16
|
357 eval_modulus(result, x2, static_cast<i2_type>(c));
|
Chris@16
|
358 }
|
Chris@16
|
359
|
Chris@16
|
360 template <class Backend, class Integer>
|
Chris@16
|
361 typename enable_if<is_unsigned<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
|
Chris@16
|
362 {
|
Chris@16
|
363 typedef typename double_precision_type<Backend>::type double_type;
|
Chris@16
|
364 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
Chris@16
|
365
|
Chris@16
|
366 using default_ops::eval_bit_test;
|
Chris@16
|
367 using default_ops::eval_get_sign;
|
Chris@16
|
368 using default_ops::eval_multiply;
|
Chris@16
|
369 using default_ops::eval_modulus;
|
Chris@16
|
370 using default_ops::eval_right_shift;
|
Chris@16
|
371
|
Chris@16
|
372 double_type x, y(a), t;
|
Chris@16
|
373 x = ui_type(1u);
|
Chris@16
|
374
|
Chris@16
|
375 while(b > 0)
|
Chris@16
|
376 {
|
Chris@16
|
377 if(b & 1)
|
Chris@16
|
378 {
|
Chris@16
|
379 eval_multiply(t, x, y);
|
Chris@16
|
380 eval_modulus(x, t, c);
|
Chris@16
|
381 }
|
Chris@16
|
382 eval_multiply(t, y, y);
|
Chris@16
|
383 eval_modulus(y, t, c);
|
Chris@16
|
384 b >>= 1;
|
Chris@16
|
385 }
|
Chris@16
|
386 Backend x2(x);
|
Chris@16
|
387 eval_modulus(result, x2, c);
|
Chris@16
|
388 }
|
Chris@16
|
389
|
Chris@16
|
390 template <class Backend, class Integer>
|
Chris@16
|
391 typename enable_if<is_signed<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
|
Chris@16
|
392 {
|
Chris@16
|
393 if(b < 0)
|
Chris@16
|
394 {
|
Chris@16
|
395 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
Chris@16
|
396 }
|
Chris@16
|
397 eval_powm(result, a, static_cast<typename make_unsigned<Integer>::type>(b), c);
|
Chris@16
|
398 }
|
Chris@16
|
399
|
Chris@16
|
400 template <class Backend, class Integer1, class Integer2>
|
Chris@16
|
401 typename enable_if<is_unsigned<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
|
Chris@16
|
402 {
|
Chris@16
|
403 typedef typename double_precision_type<Backend>::type double_type;
|
Chris@16
|
404 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
Chris@16
|
405 typedef typename boost::multiprecision::detail::canonical<Integer1, double_type>::type i1_type;
|
Chris@16
|
406 typedef typename boost::multiprecision::detail::canonical<Integer2, Backend>::type i2_type;
|
Chris@16
|
407
|
Chris@16
|
408 using default_ops::eval_bit_test;
|
Chris@16
|
409 using default_ops::eval_get_sign;
|
Chris@16
|
410 using default_ops::eval_multiply;
|
Chris@16
|
411 using default_ops::eval_modulus;
|
Chris@16
|
412 using default_ops::eval_right_shift;
|
Chris@16
|
413
|
Chris@16
|
414 double_type x, y(a), t;
|
Chris@16
|
415 x = ui_type(1u);
|
Chris@16
|
416
|
Chris@16
|
417 while(b > 0)
|
Chris@16
|
418 {
|
Chris@16
|
419 if(b & 1)
|
Chris@16
|
420 {
|
Chris@16
|
421 eval_multiply(t, x, y);
|
Chris@16
|
422 eval_modulus(x, t, static_cast<i1_type>(c));
|
Chris@16
|
423 }
|
Chris@16
|
424 eval_multiply(t, y, y);
|
Chris@16
|
425 eval_modulus(y, t, static_cast<i1_type>(c));
|
Chris@16
|
426 b >>= 1;
|
Chris@16
|
427 }
|
Chris@16
|
428 Backend x2(x);
|
Chris@16
|
429 eval_modulus(result, x2, static_cast<i2_type>(c));
|
Chris@16
|
430 }
|
Chris@16
|
431
|
Chris@16
|
432 template <class Backend, class Integer1, class Integer2>
|
Chris@16
|
433 typename enable_if<is_signed<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
|
Chris@16
|
434 {
|
Chris@16
|
435 if(b < 0)
|
Chris@16
|
436 {
|
Chris@16
|
437 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
Chris@16
|
438 }
|
Chris@16
|
439 eval_powm(result, a, static_cast<typename make_unsigned<Integer1>::type>(b), c);
|
Chris@16
|
440 }
|
Chris@16
|
441
|
Chris@16
|
442 struct powm_func
|
Chris@16
|
443 {
|
Chris@16
|
444 template <class T, class U, class V>
|
Chris@16
|
445 void operator()(T& result, const T& b, const U& p, const V& m)const
|
Chris@16
|
446 {
|
Chris@16
|
447 eval_powm(result, b, p, m);
|
Chris@16
|
448 }
|
Chris@16
|
449 };
|
Chris@16
|
450
|
Chris@16
|
451 }
|
Chris@16
|
452
|
Chris@16
|
453 template <class T, class U, class V>
|
Chris@16
|
454 inline typename enable_if<
|
Chris@16
|
455 mpl::and_<
|
Chris@16
|
456 mpl::bool_<number_category<T>::value == number_kind_integer>,
|
Chris@16
|
457 mpl::or_<
|
Chris@16
|
458 is_number<T>,
|
Chris@16
|
459 is_number_expression<T>
|
Chris@16
|
460 >,
|
Chris@16
|
461 mpl::or_<
|
Chris@16
|
462 is_number<U>,
|
Chris@16
|
463 is_number_expression<U>,
|
Chris@16
|
464 is_integral<U>
|
Chris@16
|
465 >,
|
Chris@16
|
466 mpl::or_<
|
Chris@16
|
467 is_number<V>,
|
Chris@16
|
468 is_number_expression<V>,
|
Chris@16
|
469 is_integral<V>
|
Chris@16
|
470 >
|
Chris@16
|
471 >,
|
Chris@16
|
472 detail::expression<detail::function, default_ops::powm_func, T, U, V> >::type
|
Chris@16
|
473 powm(const T& b, const U& p, const V& mod)
|
Chris@16
|
474 {
|
Chris@16
|
475 return detail::expression<detail::function, default_ops::powm_func, T, U, V>(
|
Chris@16
|
476 default_ops::powm_func(), b, p, mod);
|
Chris@16
|
477 }
|
Chris@16
|
478
|
Chris@16
|
479 }} //namespaces
|
Chris@16
|
480
|
Chris@16
|
481 #endif
|
Chris@16
|
482
|
Chris@16
|
483
|