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