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 https://www.boost.org/LICENSE_1_0.txt
6 #ifndef BOOST_MP_INT_FUNC_HPP
7 #define BOOST_MP_INT_FUNC_HPP
9 #include <boost/multiprecision/number.hpp>
11 namespace boost { namespace multiprecision {
13 namespace default_ops {
15 template <class Backend>
16 inline BOOST_MP_CXX14_CONSTEXPR void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r)
19 eval_modulus(r, x, y);
22 template <class Backend, class Integer>
23 inline BOOST_MP_CXX14_CONSTEXPR Integer eval_integer_modulus(const Backend& x, Integer val)
26 using default_ops::eval_convert_to;
27 using default_ops::eval_modulus;
28 typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type int_type;
30 eval_modulus(t, x, static_cast<int_type>(val));
32 eval_convert_to(&result, t);
38 #pragma warning(disable : 4127)
42 inline BOOST_MP_CXX14_CONSTEXPR void eval_gcd(B& result, const B& a, const B& b)
44 using default_ops::eval_get_sign;
45 using default_ops::eval_is_zero;
46 using default_ops::eval_lsb;
52 int s = eval_get_sign(u);
75 /* Let shift := lg K, where K is the greatest power of 2
76 dividing both u and v. */
78 unsigned us = eval_lsb(u);
79 unsigned vs = eval_lsb(v);
80 shift = (std::min)(us, vs);
81 eval_right_shift(u, us);
82 eval_right_shift(v, vs);
86 /* Now u and v are both odd, so diff(u, v) is even.
87 Let u = min(u, v), v = diff(u, v)/2. */
95 eval_right_shift(v, vs);
99 eval_left_shift(result, shift);
107 inline BOOST_MP_CXX14_CONSTEXPR void eval_lcm(B& result, const B& a, const B& b)
109 typedef typename mpl::front<typename B::unsigned_types>::type ui_type;
115 result = static_cast<ui_type>(0);
119 eval_divide(result, a, t);
120 eval_multiply(result, b);
122 if (eval_get_sign(result) < 0)
126 } // namespace default_ops
128 template <class Backend, expression_template_option ExpressionTemplates>
129 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
130 divide_qr(const number<Backend, ExpressionTemplates>& x, const number<Backend, ExpressionTemplates>& y,
131 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
133 using default_ops::eval_qr;
134 eval_qr(x.backend(), y.backend(), q.backend(), r.backend());
137 template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
138 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
139 divide_qr(const number<Backend, ExpressionTemplates>& x, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& y,
140 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
142 divide_qr(x, number<Backend, ExpressionTemplates>(y), q, r);
145 template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
146 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
147 divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const number<Backend, ExpressionTemplates>& y,
148 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
150 divide_qr(number<Backend, ExpressionTemplates>(x), y, q, r);
153 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>
154 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
155 divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& y,
156 number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
158 divide_qr(number<Backend, ExpressionTemplates>(x), number<Backend, ExpressionTemplates>(y), q, r);
161 template <class Backend, expression_template_option ExpressionTemplates, class Integer>
162 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<Backend>::value == number_kind_integer> >, Integer>::type
163 integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
165 using default_ops::eval_integer_modulus;
166 return eval_integer_modulus(x.backend(), val);
169 template <class tag, class A1, class A2, class A3, class A4, class Integer>
170 inline BOOST_MP_CXX14_CONSTEXPR 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
171 integer_modulus(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, Integer val)
173 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type result_type;
174 return integer_modulus(result_type(x), val);
177 template <class Backend, expression_template_option ExpressionTemplates>
178 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
179 lsb(const number<Backend, ExpressionTemplates>& x)
181 using default_ops::eval_lsb;
182 return eval_lsb(x.backend());
185 template <class tag, class A1, class A2, class A3, class A4>
186 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
187 lsb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
189 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
191 using default_ops::eval_lsb;
192 return eval_lsb(n.backend());
195 template <class Backend, expression_template_option ExpressionTemplates>
196 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
197 msb(const number<Backend, ExpressionTemplates>& x)
199 using default_ops::eval_msb;
200 return eval_msb(x.backend());
203 template <class tag, class A1, class A2, class A3, class A4>
204 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
205 msb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
207 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
209 using default_ops::eval_msb;
210 return eval_msb(n.backend());
213 template <class Backend, expression_template_option ExpressionTemplates>
214 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer, bool>::type
215 bit_test(const number<Backend, ExpressionTemplates>& x, unsigned index)
217 using default_ops::eval_bit_test;
218 return eval_bit_test(x.backend(), index);
221 template <class tag, class A1, class A2, class A3, class A4>
222 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, bool>::type
223 bit_test(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, unsigned index)
225 typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
227 using default_ops::eval_bit_test;
228 return eval_bit_test(n.backend(), index);
231 template <class Backend, expression_template_option ExpressionTemplates>
232 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
233 bit_set(number<Backend, ExpressionTemplates>& x, unsigned index)
235 using default_ops::eval_bit_set;
236 eval_bit_set(x.backend(), index);
240 template <class Backend, expression_template_option ExpressionTemplates>
241 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
242 bit_unset(number<Backend, ExpressionTemplates>& x, unsigned index)
244 using default_ops::eval_bit_unset;
245 eval_bit_unset(x.backend(), index);
249 template <class Backend, expression_template_option ExpressionTemplates>
250 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
251 bit_flip(number<Backend, ExpressionTemplates>& x, unsigned index)
253 using default_ops::eval_bit_flip;
254 eval_bit_flip(x.backend(), index);
258 namespace default_ops {
261 // Within powm, we need a type with twice as many digits as the argument type, define
262 // a traits class to obtain that type:
264 template <class Backend>
265 struct double_precision_type
267 typedef Backend type;
271 // If the exponent is a signed integer type, then we need to
272 // check the value is positive:
274 template <class Backend>
275 inline BOOST_MP_CXX14_CONSTEXPR void check_sign_of_backend(const Backend& v, const mpl::true_)
277 if (eval_get_sign(v) < 0)
279 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
282 template <class Backend>
283 inline BOOST_MP_CXX14_CONSTEXPR void check_sign_of_backend(const Backend&, const mpl::false_) {}
285 // Calculate (a^p)%c:
287 template <class Backend>
288 BOOST_MP_CXX14_CONSTEXPR void eval_powm(Backend& result, const Backend& a, const Backend& p, const Backend& c)
290 using default_ops::eval_bit_test;
291 using default_ops::eval_get_sign;
292 using default_ops::eval_modulus;
293 using default_ops::eval_multiply;
294 using default_ops::eval_right_shift;
296 typedef typename double_precision_type<Backend>::type double_type;
297 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
299 check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
301 double_type x, y(a), b(p), t;
304 while (eval_get_sign(b) > 0)
306 if (eval_bit_test(b, 0))
308 eval_multiply(t, x, y);
309 eval_modulus(x, t, c);
311 eval_multiply(t, y, y);
312 eval_modulus(y, t, c);
313 eval_right_shift(b, ui_type(1));
316 eval_modulus(result, x2, c);
319 template <class Backend, class Integer>
320 BOOST_MP_CXX14_CONSTEXPR void eval_powm(Backend& result, const Backend& a, const Backend& p, Integer c)
322 typedef typename double_precision_type<Backend>::type double_type;
323 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
324 typedef typename boost::multiprecision::detail::canonical<Integer, double_type>::type i1_type;
325 typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type i2_type;
327 using default_ops::eval_bit_test;
328 using default_ops::eval_get_sign;
329 using default_ops::eval_modulus;
330 using default_ops::eval_multiply;
331 using default_ops::eval_right_shift;
333 check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
335 if (eval_get_sign(p) < 0)
337 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
340 double_type x, y(a), b(p), t;
343 while (eval_get_sign(b) > 0)
345 if (eval_bit_test(b, 0))
347 eval_multiply(t, x, y);
348 eval_modulus(x, t, static_cast<i1_type>(c));
350 eval_multiply(t, y, y);
351 eval_modulus(y, t, static_cast<i1_type>(c));
352 eval_right_shift(b, ui_type(1));
355 eval_modulus(result, x2, static_cast<i2_type>(c));
358 template <class Backend, class Integer>
359 BOOST_MP_CXX14_CONSTEXPR typename enable_if<is_unsigned<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
361 typedef typename double_precision_type<Backend>::type double_type;
362 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
364 using default_ops::eval_bit_test;
365 using default_ops::eval_get_sign;
366 using default_ops::eval_modulus;
367 using default_ops::eval_multiply;
368 using default_ops::eval_right_shift;
370 double_type x, y(a), t;
377 eval_multiply(t, x, y);
378 eval_modulus(x, t, c);
380 eval_multiply(t, y, y);
381 eval_modulus(y, t, c);
385 eval_modulus(result, x2, c);
388 template <class Backend, class Integer>
389 BOOST_MP_CXX14_CONSTEXPR typename enable_if<is_signed<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
393 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
395 eval_powm(result, a, static_cast<typename make_unsigned<Integer>::type>(b), c);
398 template <class Backend, class Integer1, class Integer2>
399 BOOST_MP_CXX14_CONSTEXPR typename enable_if<is_unsigned<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
401 typedef typename double_precision_type<Backend>::type double_type;
402 typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
403 typedef typename boost::multiprecision::detail::canonical<Integer1, double_type>::type i1_type;
404 typedef typename boost::multiprecision::detail::canonical<Integer2, Backend>::type i2_type;
406 using default_ops::eval_bit_test;
407 using default_ops::eval_get_sign;
408 using default_ops::eval_modulus;
409 using default_ops::eval_multiply;
410 using default_ops::eval_right_shift;
412 double_type x, y(a), t;
419 eval_multiply(t, x, y);
420 eval_modulus(x, t, static_cast<i1_type>(c));
422 eval_multiply(t, y, y);
423 eval_modulus(y, t, static_cast<i1_type>(c));
427 eval_modulus(result, x2, static_cast<i2_type>(c));
430 template <class Backend, class Integer1, class Integer2>
431 BOOST_MP_CXX14_CONSTEXPR typename enable_if<is_signed<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
435 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
437 eval_powm(result, a, static_cast<typename make_unsigned<Integer1>::type>(b), c);
442 template <class T, class U, class V>
443 BOOST_MP_CXX14_CONSTEXPR void operator()(T& result, const T& b, const U& p, const V& m) const
445 eval_powm(result, b, p, m);
449 } // namespace default_ops
451 template <class T, class U, class V>
452 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if<
454 mpl::bool_<number_category<T>::value == number_kind_integer>,
457 is_number_expression<T> >,
460 is_number_expression<U>,
464 is_number_expression<V>,
475 detail::expression<detail::function, default_ops::powm_func, T, U, V> >::type>::type>::type>::type
476 powm(const T& b, const U& p, const V& mod)
478 return detail::expression<detail::function, default_ops::powm_func, T, U, V>(
479 default_ops::powm_func(), b, p, mod);
482 }} // namespace boost::multiprecision