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 // Comparison operators for cpp_int_backend:
8 #ifndef BOOST_MP_CPP_INT_MISC_HPP
9 #define BOOST_MP_CPP_INT_MISC_HPP
11 #include <boost/multiprecision/detail/constexpr.hpp>
12 #include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
13 #include <boost/integer/common_factor_rt.hpp> // gcd/lcm
14 #include <boost/functional/hash_fwd.hpp>
18 #pragma warning(disable : 4702)
19 #pragma warning(disable : 4127) // conditional expression is constant
20 #pragma warning(disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
23 namespace boost { namespace multiprecision { namespace backends {
25 template <class R, class CppInt>
26 BOOST_MP_CXX14_CONSTEXPR void check_in_range(const CppInt& val, const mpl::int_<checked>&)
28 typedef typename boost::multiprecision::detail::canonical<R, CppInt>::type cast_type;
31 if (boost::is_signed<R>::value == false)
32 BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
33 if (val.compare(static_cast<cast_type>((std::numeric_limits<R>::min)())) < 0)
34 BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
38 if (val.compare(static_cast<cast_type>((std::numeric_limits<R>::max)())) > 0)
39 BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
42 template <class R, class CppInt>
43 inline BOOST_MP_CXX14_CONSTEXPR void check_in_range(const CppInt& /*val*/, const mpl::int_<unchecked>&) BOOST_NOEXCEPT {}
45 inline BOOST_MP_CXX14_CONSTEXPR void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {}
46 inline void check_is_negative(const mpl::false_&)
48 BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
51 template <class Integer>
52 inline BOOST_MP_CXX14_CONSTEXPR Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT
56 template <class Integer>
57 inline BOOST_MP_CXX14_CONSTEXPR Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT
62 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
63 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
64 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend)
66 typedef mpl::int_<Checked1> checked_type;
67 check_in_range<R>(backend, checked_type());
69 if (std::numeric_limits<R>::digits < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
71 if ((backend.sign() && boost::is_signed<R>::value) && (1 + static_cast<boost::multiprecision::limb_type>((std::numeric_limits<R>::max)()) <= backend.limbs()[0]))
73 *result = (std::numeric_limits<R>::min)();
76 else if (boost::is_signed<R>::value && !backend.sign() && static_cast<boost::multiprecision::limb_type>((std::numeric_limits<R>::max)()) <= backend.limbs()[0])
78 *result = (std::numeric_limits<R>::max)();
82 *result = static_cast<R>(backend.limbs()[0]);
85 *result = static_cast<R>(backend.limbs()[0]);
86 unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
88 if (std::numeric_limits<R>::digits > cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
90 while ((i < backend.size()) && (shift < static_cast<unsigned>(std::numeric_limits<R>::digits - cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)))
92 *result += static_cast<R>(backend.limbs()[i]) << shift;
93 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
97 // We have one more limb to extract, but may not need all the bits, so treat this as a special case:
99 if (i < backend.size())
101 const limb_type mask = std::numeric_limits<R>::digits - shift == cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits ? ~static_cast<limb_type>(0) : (static_cast<limb_type>(1u) << (std::numeric_limits<R>::digits - shift)) - 1;
102 *result += (static_cast<R>(backend.limbs()[i]) & mask) << shift;
103 if ((static_cast<R>(backend.limbs()[i]) & static_cast<limb_type>(~mask)) || (i + 1 < backend.size()))
108 check_is_negative(boost::is_signed<R>());
109 *result = (std::numeric_limits<R>::min)();
111 else if (boost::is_signed<R>::value)
112 *result = (std::numeric_limits<R>::max)();
117 else if (backend.size() > 1)
122 check_is_negative(boost::is_signed<R>());
123 *result = (std::numeric_limits<R>::min)();
125 else if (boost::is_signed<R>::value)
126 *result = (std::numeric_limits<R>::max)();
131 check_is_negative(mpl::bool_<boost::is_signed<R>::value>());
132 *result = negate_integer(*result, mpl::bool_<boost::is_signed<R>::value>());
136 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
137 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_floating_point<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
138 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_MP_NOEXCEPT_IF(is_arithmetic<R>::value)
140 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
141 unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
142 *result = static_cast<R>(*p);
143 for (unsigned i = 1; i < backend.size(); ++i)
145 *result += static_cast<R>(std::ldexp(static_cast<long double>(p[i]), shift));
146 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
152 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
153 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
154 eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
156 return (val.size() == 1) && (val.limbs()[0] == 0);
158 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
159 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
160 eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
162 return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
164 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
165 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
166 eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
173 // Get the location of the least-significant-bit:
175 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
176 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
177 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
179 using default_ops::eval_get_sign;
180 if (eval_get_sign(a) == 0)
182 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
186 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
190 // Find the index of the least significant limb that is non-zero:
193 while (!a.limbs()[index] && (index < a.size()))
196 // Find the index of the least significant bit within that limb:
198 unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
200 return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
204 // Get the location of the most-significant-bit:
206 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
207 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
208 eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
211 // Find the index of the most significant bit that is non-zero:
213 return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
216 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
217 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
218 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
220 using default_ops::eval_get_sign;
221 if (eval_get_sign(a) == 0)
223 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
227 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
229 return eval_msb_imp(a);
232 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
233 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
234 eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
236 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
237 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
238 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
239 if (offset >= val.size())
241 return val.limbs()[offset] & mask ? true : false;
244 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
245 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
246 eval_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
248 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
249 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
250 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
251 if (offset >= val.size())
253 unsigned os = val.size();
254 val.resize(offset + 1, offset + 1);
255 if (offset >= val.size())
256 return; // fixed precision overflow
257 for (unsigned i = os; i <= offset; ++i)
260 val.limbs()[offset] |= mask;
263 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
264 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
265 eval_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
267 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
268 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
269 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
270 if (offset >= val.size())
272 val.limbs()[offset] &= ~mask;
276 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
277 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
278 eval_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
280 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
281 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
282 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
283 if (offset >= val.size())
285 unsigned os = val.size();
286 val.resize(offset + 1, offset + 1);
287 if (offset >= val.size())
288 return; // fixed precision overflow
289 for (unsigned i = os; i <= offset; ++i)
292 val.limbs()[offset] ^= mask;
296 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
297 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
299 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
300 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
301 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
302 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
304 divide_unsigned_helper(&q, x, y, r);
305 q.sign(x.sign() != y.sign());
309 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
310 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
312 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
314 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
315 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
317 divide_unsigned_helper(&q, x, y, r);
322 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
323 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<U>::value>::type eval_qr(
324 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
326 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
327 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
329 using default_ops::eval_qr;
330 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
335 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
336 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
337 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
339 if ((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits<limb_type>::max)()))
341 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> d;
342 divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>*>(0), x, static_cast<limb_type>(val), d);
347 return default_ops::eval_integer_modulus(x, val);
351 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
352 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_signed<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
353 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
355 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
358 inline BOOST_MP_CXX14_CONSTEXPR limb_type integer_gcd_reduce(limb_type u, limb_type v)
363 std_constexpr::swap(u, v);
367 v >>= boost::multiprecision::detail::find_lsb(v);
372 inline BOOST_MP_CXX14_CONSTEXPR double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v)
377 std_constexpr::swap(u, v);
380 if (v <= ~static_cast<limb_type>(0))
382 u = integer_gcd_reduce(static_cast<limb_type>(v), static_cast<limb_type>(u));
386 #ifdef __MSVC_RUNTIME_CHECKS
387 while ((v & 1u) == 0)
389 while ((static_cast<unsigned>(v) & 1u) == 0)
396 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
397 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
399 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
400 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
403 using default_ops::eval_get_sign;
404 using default_ops::eval_is_zero;
405 using default_ops::eval_lsb;
407 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a);
409 int s = eval_get_sign(u);
427 /* Let shift := lg K, where K is the greatest power of 2
428 dividing both u and v. */
430 unsigned us = eval_lsb(u);
431 unsigned vs = boost::multiprecision::detail::find_lsb(v);
432 int shift = (std::min)(us, vs);
433 eval_right_shift(u, us);
439 /* Now u and v are both odd, so diff(u, v) is even.
440 Let u = min(u, v), v = diff(u, v)/2. */
444 v = integer_gcd_reduce(*u.limbs(), v);
447 double_limb_type i = u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
448 v = static_cast<limb_type>(integer_gcd_reduce(i, static_cast<double_limb_type>(v)));
454 eval_right_shift(u, us);
458 eval_left_shift(result, shift);
460 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
461 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
463 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
464 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
467 eval_gcd(result, a, static_cast<limb_type>(v));
469 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
470 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_signed<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
472 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
473 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
476 eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
479 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
480 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
482 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
483 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
484 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b)
486 using default_ops::eval_get_sign;
487 using default_ops::eval_is_zero;
488 using default_ops::eval_lsb;
492 eval_gcd(result, b, *a.limbs());
497 eval_gcd(result, a, *b.limbs());
501 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a), v(b);
503 int s = eval_get_sign(u);
515 s = eval_get_sign(v);
526 /* Let shift := lg K, where K is the greatest power of 2
527 dividing both u and v. */
529 unsigned us = eval_lsb(u);
530 unsigned vs = eval_lsb(v);
531 int shift = (std::min)(us, vs);
532 eval_right_shift(u, us);
533 eval_right_shift(v, vs);
537 /* Now u and v are both odd, so diff(u, v) is even.
538 Let u = min(u, v), v = diff(u, v)/2. */
547 u = integer_gcd_reduce(*v.limbs(), *u.limbs());
550 double_limb_type i = v.limbs()[0] | (static_cast<double_limb_type>(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
551 double_limb_type j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
552 u = integer_gcd_reduce(i, j);
558 eval_right_shift(v, vs);
562 eval_left_shift(result, shift);
565 // Now again for trivial backends:
567 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
568 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
569 eval_gcd(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT
571 *result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs());
573 // This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version:
574 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
575 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
576 eval_lcm(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, 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))
578 *result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs());
579 result.normalize(); // result may overflow the specified number of bits
582 inline void conversion_overflow(const mpl::int_<checked>&)
584 BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
586 inline BOOST_MP_CXX14_CONSTEXPR void conversion_overflow(const mpl::int_<unchecked>&) {}
588 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
589 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
590 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value>::type
591 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
593 typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
594 if (std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
598 check_is_negative(mpl::bool_ < boost::is_signed<R>::value || (number_category<R>::value == number_kind_floating_point) > ());
599 if (static_cast<common_type>(*val.limbs()) > -static_cast<common_type>((std::numeric_limits<R>::min)()))
600 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
601 *result = (std::numeric_limits<R>::min)();
605 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
606 *result = boost::is_signed<R>::value ? (std::numeric_limits<R>::max)() : static_cast<R>(*val.limbs());
611 *result = static_cast<R>(*val.limbs());
614 check_is_negative(mpl::bool_ < boost::is_signed<R>::value || (number_category<R>::value == number_kind_floating_point) > ());
615 *result = negate_integer(*result, mpl::bool_ < is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point) > ());
620 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
621 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
622 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value>::type
623 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
625 typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
626 if (std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
628 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
629 *result = boost::is_signed<R>::value ? (std::numeric_limits<R>::max)() : static_cast<R>(*val.limbs());
632 *result = static_cast<R>(*val.limbs());
635 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
636 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
637 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
639 using default_ops::eval_get_sign;
640 if (eval_get_sign(a) == 0)
642 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
646 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
649 // Find the index of the least significant bit within that limb:
651 return boost::multiprecision::detail::find_lsb(*a.limbs());
654 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
655 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
656 eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
659 // Find the index of the least significant bit within that limb:
661 return boost::multiprecision::detail::find_msb(*a.limbs());
664 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
665 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
666 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
668 using default_ops::eval_get_sign;
669 if (eval_get_sign(a) == 0)
671 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
675 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
677 return eval_msb_imp(a);
680 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
681 inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
683 std::size_t result = 0;
684 for (unsigned i = 0; i < val.size(); ++i)
686 boost::hash_combine(result, val.limbs()[i]);
688 boost::hash_combine(result, val.sign());
696 }}} // namespace boost::multiprecision::backends