Chris@16: /////////////////////////////////////////////////////////////// Chris@16: // Copyright 2012 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ Chris@16: // Chris@16: // Comparison operators for cpp_int_backend: Chris@16: // Chris@16: #ifndef BOOST_MP_CPP_INT_MISC_HPP Chris@16: #define BOOST_MP_CPP_INT_MISC_HPP Chris@16: Chris@16: #include // lsb etc Chris@101: #include // gcd/lcm Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4702) Chris@16: #endif Chris@16: Chris@16: namespace boost{ namespace multiprecision{ namespace backends{ Chris@16: Chris@16: template Chris@16: void check_in_range(const CppInt& val, const mpl::int_&) Chris@16: { Chris@16: typedef typename boost::multiprecision::detail::canonical::type cast_type; Chris@16: if(val.sign()) Chris@16: { Chris@16: if(val.compare(static_cast((std::numeric_limits::min)())) < 0) Chris@16: BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range.")); Chris@16: } Chris@16: else Chris@16: { Chris@16: if(val.compare(static_cast((std::numeric_limits::max)())) > 0) Chris@16: BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range.")); Chris@16: } Chris@16: } Chris@16: template Chris@16: inline void check_in_range(const CppInt& /*val*/, const mpl::int_&) BOOST_NOEXCEPT {} Chris@16: Chris@16: inline void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {} Chris@16: inline void check_is_negative(const mpl::false_&) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type.")); Chris@16: } Chris@16: Chris@16: template Chris@16: inline Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT Chris@16: { Chris@16: return -i; Chris@16: } Chris@16: template Chris@16: inline Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT Chris@16: { Chris@16: return ~(i-1); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value && !is_trivial_cpp_int >::value, void>::type Chris@16: eval_convert_to(R* result, const cpp_int_backend& backend) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: typedef mpl::int_ checked_type; Chris@16: check_in_range(backend, checked_type()); Chris@16: Chris@16: *result = static_cast(backend.limbs()[0]); Chris@16: unsigned shift = cpp_int_backend::limb_bits; Chris@16: for(unsigned i = 1; (i < backend.size()) && (shift < static_cast(std::numeric_limits::digits)); ++i) Chris@16: { Chris@16: *result += static_cast(backend.limbs()[i]) << shift; Chris@16: shift += cpp_int_backend::limb_bits; Chris@16: } Chris@16: if(backend.sign()) Chris@16: { Chris@16: check_is_negative(boost::is_signed()); Chris@16: *result = negate_integer(*result, boost::is_signed()); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c::value && !is_trivial_cpp_int >::value, void>::type Chris@16: eval_convert_to(R* result, const cpp_int_backend& backend) BOOST_NOEXCEPT_IF(is_arithmetic::value) Chris@16: { Chris@16: typename cpp_int_backend::const_limb_pointer p = backend.limbs(); Chris@16: unsigned shift = cpp_int_backend::limb_bits; Chris@16: *result = static_cast(*p); Chris@16: for(unsigned i = 1; i < backend.size(); ++i) Chris@16: { Chris@16: *result += static_cast(std::ldexp(static_cast(p[i]), shift)); Chris@16: shift += cpp_int_backend::limb_bits; Chris@16: } Chris@16: if(backend.sign()) Chris@16: *result = -*result; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value, bool>::type Chris@16: eval_is_zero(const cpp_int_backend& val) BOOST_NOEXCEPT Chris@16: { Chris@16: return (val.size() == 1) && (val.limbs()[0] == 0); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value, int>::type Chris@16: eval_get_sign(const cpp_int_backend& val) BOOST_NOEXCEPT Chris@16: { Chris@16: return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1; Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_abs(cpp_int_backend& result, const cpp_int_backend& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: result = val; Chris@16: result.sign(false); Chris@16: } Chris@16: Chris@16: // Chris@16: // Get the location of the least-significant-bit: Chris@16: // Chris@16: template Chris@16: inline typename enable_if_c >::value, unsigned>::type Chris@16: eval_lsb(const cpp_int_backend& a) Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: if(eval_get_sign(a) == 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); Chris@16: } Chris@16: if(a.sign()) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); Chris@16: } Chris@16: Chris@16: // Chris@16: // Find the index of the least significant limb that is non-zero: Chris@16: // Chris@16: unsigned index = 0; Chris@16: while(!a.limbs()[index] && (index < a.size())) Chris@16: ++index; Chris@16: // Chris@16: // Find the index of the least significant bit within that limb: Chris@16: // Chris@16: unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]); Chris@16: Chris@16: return result + index * cpp_int_backend::limb_bits; Chris@16: } Chris@16: Chris@16: // Chris@16: // Get the location of the most-significant-bit: Chris@16: // Chris@16: template Chris@16: inline typename enable_if_c >::value, unsigned>::type Chris@16: eval_msb(const cpp_int_backend& a) Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: if(eval_get_sign(a) == 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); Chris@16: } Chris@16: if(a.sign()) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); Chris@16: } Chris@16: Chris@16: // Chris@16: // Find the index of the most significant bit that is non-zero: Chris@16: // Chris@16: return (a.size() - 1) * cpp_int_backend::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value, bool>::type Chris@16: eval_bit_test(const cpp_int_backend& val, unsigned index) BOOST_NOEXCEPT Chris@16: { Chris@16: unsigned offset = index / cpp_int_backend::limb_bits; Chris@16: unsigned shift = index % cpp_int_backend::limb_bits; Chris@16: limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); Chris@16: if(offset >= val.size()) Chris@16: return false; Chris@16: return val.limbs()[offset] & mask ? true : false; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value>::type Chris@16: eval_bit_set(cpp_int_backend& val, unsigned index) Chris@16: { Chris@16: unsigned offset = index / cpp_int_backend::limb_bits; Chris@16: unsigned shift = index % cpp_int_backend::limb_bits; Chris@16: limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); Chris@16: if(offset >= val.size()) Chris@16: { Chris@16: unsigned os = val.size(); Chris@16: val.resize(offset + 1, offset + 1); Chris@16: if(offset >= val.size()) Chris@16: return; // fixed precision overflow Chris@16: for(unsigned i = os; i <= offset; ++i) Chris@16: val.limbs()[i] = 0; Chris@16: } Chris@16: val.limbs()[offset] |= mask; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value>::type Chris@16: eval_bit_unset(cpp_int_backend& val, unsigned index) BOOST_NOEXCEPT Chris@16: { Chris@16: unsigned offset = index / cpp_int_backend::limb_bits; Chris@16: unsigned shift = index % cpp_int_backend::limb_bits; Chris@16: limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); Chris@16: if(offset >= val.size()) Chris@16: return; Chris@16: val.limbs()[offset] &= ~mask; Chris@16: val.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value>::type Chris@16: eval_bit_flip(cpp_int_backend& val, unsigned index) Chris@16: { Chris@16: unsigned offset = index / cpp_int_backend::limb_bits; Chris@16: unsigned shift = index % cpp_int_backend::limb_bits; Chris@16: limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u); Chris@16: if(offset >= val.size()) Chris@16: { Chris@16: unsigned os = val.size(); Chris@16: val.resize(offset + 1, offset + 1); Chris@16: if(offset >= val.size()) Chris@16: return; // fixed precision overflow Chris@16: for(unsigned i = os; i <= offset; ++i) Chris@16: val.limbs()[i] = 0; Chris@16: } Chris@16: val.limbs()[offset] ^= mask; Chris@16: val.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value>::type Chris@16: eval_qr( Chris@16: const cpp_int_backend& x, Chris@16: const cpp_int_backend& y, Chris@16: cpp_int_backend& q, Chris@16: cpp_int_backend& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: divide_unsigned_helper(&q, x, y, r); Chris@16: q.sign(x.sign() != y.sign()); Chris@16: r.sign(x.sign()); Chris@16: } Chris@16: Chris@101: template Chris@101: inline typename enable_if_c >::value>::type Chris@101: eval_qr( Chris@101: const cpp_int_backend& x, Chris@101: limb_type y, Chris@101: cpp_int_backend& q, Chris@101: cpp_int_backend& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@101: { Chris@101: divide_unsigned_helper(&q, x, y, r); Chris@101: q.sign(x.sign()); Chris@101: r.sign(x.sign()); Chris@101: } Chris@101: Chris@101: template Chris@101: inline typename enable_if_c::value>::type eval_qr( Chris@101: const cpp_int_backend& x, Chris@101: U y, Chris@101: cpp_int_backend& q, Chris@101: cpp_int_backend& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@101: { Chris@101: using default_ops::eval_qr; Chris@101: cpp_int_backend t(y); Chris@101: eval_qr(x, t, q, r); Chris@101: } Chris@101: Chris@16: template Chris@16: inline typename enable_if_c::value && !is_trivial_cpp_int >::value, Integer>::type Chris@16: eval_integer_modulus(const cpp_int_backend& x, Integer val) Chris@16: { Chris@16: if((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits::max)())) Chris@16: { Chris@16: cpp_int_backend d; Chris@16: divide_unsigned_helper(static_cast*>(0), x, static_cast(val), d); Chris@16: return d.limbs()[0]; Chris@16: } Chris@16: else Chris@16: { Chris@16: return default_ops::eval_integer_modulus(x, val); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c::value && !is_trivial_cpp_int >::value, Integer>::type Chris@16: eval_integer_modulus(const cpp_int_backend& x, Integer val) Chris@16: { Chris@101: return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val)); Chris@16: } Chris@16: Chris@16: inline limb_type integer_gcd_reduce(limb_type u, limb_type v) Chris@16: { Chris@16: do Chris@16: { Chris@16: if(u > v) Chris@16: std::swap(u, v); Chris@16: if(u == v) Chris@16: break; Chris@16: v -= u; Chris@16: v >>= boost::multiprecision::detail::find_lsb(v); Chris@16: } while(true); Chris@16: return u; Chris@16: } Chris@16: Chris@16: inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v) Chris@16: { Chris@16: do Chris@16: { Chris@16: if(u > v) Chris@16: std::swap(u, v); Chris@16: if(u == v) Chris@16: break; Chris@16: if(v <= ~static_cast(0)) Chris@16: { Chris@16: u = integer_gcd_reduce(static_cast(v), static_cast(u)); Chris@16: break; Chris@16: } Chris@16: v -= u; Chris@16: while((static_cast(v) & 1u) == 0) Chris@16: v >>= 1; Chris@16: } while(true); Chris@16: return u; Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value>::type Chris@16: eval_gcd( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: limb_type v) Chris@16: { Chris@16: using default_ops::eval_lsb; Chris@16: using default_ops::eval_is_zero; Chris@16: using default_ops::eval_get_sign; Chris@16: Chris@16: int shift; Chris@16: Chris@16: cpp_int_backend u(a); Chris@16: Chris@16: int s = eval_get_sign(u); Chris@16: Chris@16: /* GCD(0,x) := x */ Chris@16: if(s < 0) Chris@16: { Chris@16: u.negate(); Chris@16: } Chris@16: else if(s == 0) Chris@16: { Chris@16: result = v; Chris@16: return; Chris@16: } Chris@16: if(v == 0) Chris@16: { Chris@16: result = u; Chris@16: return; Chris@16: } Chris@16: Chris@16: /* Let shift := lg K, where K is the greatest power of 2 Chris@16: dividing both u and v. */ Chris@16: Chris@16: unsigned us = eval_lsb(u); Chris@16: unsigned vs = boost::multiprecision::detail::find_lsb(v); Chris@16: shift = (std::min)(us, vs); Chris@16: eval_right_shift(u, us); Chris@16: if(vs) Chris@16: v >>= vs; Chris@16: Chris@16: do Chris@16: { Chris@16: /* Now u and v are both odd, so diff(u, v) is even. Chris@16: Let u = min(u, v), v = diff(u, v)/2. */ Chris@16: if(u.size() <= 2) Chris@16: { Chris@16: if(u.size() == 1) Chris@16: v = integer_gcd_reduce(*u.limbs(), v); Chris@16: else Chris@16: { Chris@16: double_limb_type i; Chris@16: i = u.limbs()[0] | (static_cast(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT); Chris@16: v = static_cast(integer_gcd_reduce(i, static_cast(v))); Chris@16: } Chris@16: break; Chris@16: } Chris@16: eval_subtract(u, v); Chris@16: us = eval_lsb(u); Chris@16: eval_right_shift(u, us); Chris@16: } Chris@16: while(true); Chris@16: Chris@16: result = v; Chris@16: eval_left_shift(result, shift); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int >::value>::type Chris@16: eval_gcd( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const Integer& v) Chris@16: { Chris@16: eval_gcd(result, a, static_cast(v)); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int >::value>::type Chris@16: eval_gcd( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const Integer& v) Chris@16: { Chris@16: eval_gcd(result, a, static_cast(v < 0 ? -v : v)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value>::type Chris@16: eval_gcd( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const cpp_int_backend& b) Chris@16: { Chris@16: using default_ops::eval_lsb; Chris@16: using default_ops::eval_is_zero; Chris@16: using default_ops::eval_get_sign; Chris@16: Chris@16: if(a.size() == 1) Chris@16: { Chris@16: eval_gcd(result, b, *a.limbs()); Chris@16: return; Chris@16: } Chris@16: if(b.size() == 1) Chris@16: { Chris@16: eval_gcd(result, a, *b.limbs()); Chris@16: return; Chris@16: } Chris@16: Chris@16: int shift; Chris@16: Chris@16: cpp_int_backend u(a), v(b); Chris@16: Chris@16: int s = eval_get_sign(u); Chris@16: Chris@16: /* GCD(0,x) := x */ Chris@16: if(s < 0) Chris@16: { Chris@16: u.negate(); Chris@16: } Chris@16: else if(s == 0) Chris@16: { Chris@16: result = v; Chris@16: return; Chris@16: } Chris@16: s = eval_get_sign(v); Chris@16: if(s < 0) Chris@16: { Chris@16: v.negate(); Chris@16: } Chris@16: else if(s == 0) Chris@16: { Chris@16: result = u; Chris@16: return; Chris@16: } Chris@16: Chris@16: /* Let shift := lg K, where K is the greatest power of 2 Chris@16: dividing both u and v. */ Chris@16: Chris@16: unsigned us = eval_lsb(u); Chris@16: unsigned vs = eval_lsb(v); Chris@16: shift = (std::min)(us, vs); Chris@16: eval_right_shift(u, us); Chris@16: eval_right_shift(v, vs); Chris@16: Chris@16: do Chris@16: { Chris@16: /* Now u and v are both odd, so diff(u, v) is even. Chris@16: Let u = min(u, v), v = diff(u, v)/2. */ Chris@16: s = u.compare(v); Chris@16: if(s > 0) Chris@16: u.swap(v); Chris@16: if(s == 0) Chris@16: break; Chris@16: if(v.size() <= 2) Chris@16: { Chris@16: if(v.size() == 1) Chris@16: u = integer_gcd_reduce(*v.limbs(), *u.limbs()); Chris@16: else Chris@16: { Chris@16: double_limb_type i, j; Chris@16: i = v.limbs()[0] | (static_cast(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT); Chris@16: j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT); Chris@16: u = integer_gcd_reduce(i, j); Chris@16: } Chris@16: break; Chris@16: } Chris@16: eval_subtract(v, u); Chris@16: vs = eval_lsb(v); Chris@16: eval_right_shift(v, vs); Chris@16: } Chris@16: while(true); Chris@16: Chris@16: result = u; Chris@16: eval_left_shift(result, shift); Chris@16: } Chris@16: // Chris@16: // Now again for trivial backends: Chris@16: // Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_gcd(cpp_int_backend& result, const cpp_int_backend& a, const cpp_int_backend& b) BOOST_NOEXCEPT Chris@16: { Chris@101: *result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs()); Chris@16: } Chris@16: // This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && (Checked1 == unchecked)>::type Chris@16: eval_lcm(cpp_int_backend& result, const cpp_int_backend& a, const cpp_int_backend& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@101: *result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs()); Chris@16: result.normalize(); // result may overflow the specified number of bits Chris@16: } Chris@16: Chris@16: inline void conversion_overflow(const mpl::int_&) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type")); Chris@16: } Chris@16: inline void conversion_overflow(const mpl::int_&){} Chris@16: Chris@16: template Chris@16: inline typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_signed_number >::value Chris@16: >::type Chris@16: eval_convert_to(R* result, const cpp_int_backend& val) Chris@16: { Chris@16: typedef typename common_type::local_limb_type>::type common_type; Chris@16: if(std::numeric_limits::is_specialized && (static_cast(*val.limbs()) > static_cast((std::numeric_limits::max)()))) Chris@16: { Chris@16: conversion_overflow(typename cpp_int_backend::checked_type()); Chris@16: *result = (std::numeric_limits::max)(); Chris@16: } Chris@16: else Chris@16: *result = static_cast(*val.limbs()); Chris@16: if(val.isneg()) Chris@16: { Chris@16: check_is_negative(mpl::bool_::value || boost::is_floating_point::value>()); Chris@16: *result = negate_integer(*result, mpl::bool_::value || boost::is_floating_point::value>()); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_unsigned_number >::value Chris@16: >::type Chris@16: eval_convert_to(R* result, const cpp_int_backend& val) Chris@16: { Chris@16: typedef typename common_type::local_limb_type>::type common_type; Chris@16: if(std::numeric_limits::is_specialized && (static_cast(*val.limbs()) > static_cast((std::numeric_limits::max)()))) Chris@16: { Chris@16: conversion_overflow(typename cpp_int_backend::checked_type()); Chris@16: *result = (std::numeric_limits::max)(); Chris@16: } Chris@16: else Chris@16: *result = static_cast(*val.limbs()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value, unsigned>::type Chris@16: eval_lsb(const cpp_int_backend& a) Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: if(eval_get_sign(a) == 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); Chris@16: } Chris@16: if(a.sign()) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); Chris@16: } Chris@16: // Chris@16: // Find the index of the least significant bit within that limb: Chris@16: // Chris@16: return boost::multiprecision::detail::find_lsb(*a.limbs()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename enable_if_c >::value, unsigned>::type Chris@16: eval_msb(const cpp_int_backend& a) Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: if(eval_get_sign(a) == 0) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand.")); Chris@16: } Chris@16: if(a.sign()) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined.")); Chris@16: } Chris@16: // Chris@16: // Find the index of the least significant bit within that limb: Chris@16: // Chris@16: return boost::multiprecision::detail::find_msb(*a.limbs()); Chris@16: } Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: }}} // namespaces Chris@16: Chris@16: #endif