diff options
Diffstat (limited to 'boost/multiprecision/cpp_int/bitwise.hpp')
-rw-r--r-- | boost/multiprecision/cpp_int/bitwise.hpp | 426 |
1 files changed, 302 insertions, 124 deletions
diff --git a/boost/multiprecision/cpp_int/bitwise.hpp b/boost/multiprecision/cpp_int/bitwise.hpp index dd6ba9d191..e39be3d12c 100644 --- a/boost/multiprecision/cpp_int/bitwise.hpp +++ b/boost/multiprecision/cpp_int/bitwise.hpp @@ -306,30 +306,86 @@ BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned_number<cpp_int_backend<Min result.normalize(); } -template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> -inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type - eval_left_shift( - cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, - double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +template <class Int> +inline void left_shift_byte(Int& result, double_limb_type s) { - is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); - if(!s) + limb_type offset = static_cast<limb_type>(s / Int::limb_bits); + limb_type shift = static_cast<limb_type>(s % Int::limb_bits); + unsigned ors = result.size(); + if((ors == 1) && (!*result.limbs())) + return; // shifting zero yields zero. + unsigned rs = ors; + if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift))) + ++rs; // Most significant limb will overflow when shifted + rs += offset; + result.resize(rs, rs); + rs = result.size(); + + typename Int::limb_pointer pr = result.limbs(); + + if(rs != ors) + pr[rs - 1] = 0u; + std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT); + std::size_t len = std::min(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes); + if(bytes >= rs * sizeof(limb_type)) + result = static_cast<limb_type>(0u); + else + { + unsigned char* pc = reinterpret_cast<unsigned char*>(pr); + std::memmove(pc + bytes, pc, len); + std::memset(pc, 0, bytes); + } +} + +template <class Int> +inline void left_shift_limb(Int& result, double_limb_type s) +{ + limb_type offset = static_cast<limb_type>(s / Int::limb_bits); + limb_type shift = static_cast<limb_type>(s % Int::limb_bits); + + unsigned ors = result.size(); + if((ors == 1) && (!*result.limbs())) + return; // shifting zero yields zero. + unsigned rs = ors; + if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift))) + ++rs; // Most significant limb will overflow when shifted + rs += offset; + result.resize(rs, rs); + bool truncated = result.size() != rs; + + typename Int::limb_pointer pr = result.limbs(); + + if(offset > rs) + { + // The result is shifted past the end of the result: + result = static_cast<limb_type>(0); return; + } - limb_type offset = static_cast<limb_type>(s / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits); - limb_type shift = static_cast<limb_type>(s % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits); + unsigned i = rs - result.size(); + for(; i < ors; ++i) + pr[rs - 1 - i] = pr[ors - 1 - i]; + for(; i < rs; ++i) + pr[rs - 1 - i] = 0; +} + +template <class Int> +inline void left_shift_generic(Int& result, double_limb_type s) +{ + limb_type offset = static_cast<limb_type>(s / Int::limb_bits); + limb_type shift = static_cast<limb_type>(s % Int::limb_bits); unsigned ors = result.size(); if((ors == 1) && (!*result.limbs())) return; // shifting zero yields zero. unsigned rs = ors; - if(shift && (result.limbs()[ors - 1] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift))) + if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift))) ++rs; // Most significant limb will overflow when shifted rs += offset; result.resize(rs, rs); bool truncated = result.size() != rs; - typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs(); + typename Int::limb_pointer pr = result.limbs(); if(offset > rs) { @@ -339,53 +395,40 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit } unsigned i = rs - result.size(); - if(shift) + // This code only works when shift is non-zero, otherwise we invoke undefined behaviour! + BOOST_ASSERT(shift); + if(!truncated) { - // This code only works when shift is non-zero, otherwise we invoke undefined behaviour! - if(!truncated) - { - if(rs > ors + offset) - { - pr[rs - 1 - i] = pr[ors - 1 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift); - --rs; - } - else - { - pr[rs - 1 - i] = pr[ors - 1 - i] << shift; - if(ors > 1) - pr[rs - 1 - i] |= pr[ors - 2 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift); - ++i; - } - } - for(; ors > 1 + i; ++i) + if(rs > ors + offset) { - pr[rs - 1 - i] = pr[ors - 1 - i] << shift; - pr[rs - 1 - i] |= pr[ors - 2 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift); + pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift); + --rs; } - if(ors >= 1 + i) + else { pr[rs - 1 - i] = pr[ors - 1 - i] << shift; + if(ors > 1) + pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift); ++i; } - for(; i < rs; ++i) - pr[rs - 1 - i] = 0; } - else + for(; ors > 1 + i; ++i) { - for(; i < ors; ++i) - pr[rs - 1 - i] = pr[ors - 1 - i]; - for(; i < rs; ++i) - pr[rs - 1 - i] = 0; + pr[rs - 1 - i] = pr[ors - 1 - i] << shift; + pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift); } - // - // We may have shifted off the end and have leading zeros: - // - result.normalize(); + if(ors >= 1 + i) + { + pr[rs - 1 - i] = pr[ors - 1 - i] << shift; + ++i; + } + for(; i < rs; ++i) + pr[rs - 1 - i] = 0; } template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1> inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type - eval_right_shift( + eval_left_shift( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) { @@ -393,51 +436,184 @@ inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBit if(!s) return; - bool is_neg = result.sign(); - if(is_neg) - eval_increment(result); +#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT) + static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1; + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & limb_shift_mask) == 0) + { + left_shift_limb(result, s); + } + else if((s & byte_shift_mask) == 0) + { + left_shift_byte(result, s); + } +#elif defined(BOOST_LITTLE_ENDIAN) + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & byte_shift_mask) == 0) + { + left_shift_byte(result, s); + } +#else + static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1; + if((s & limb_shift_mask) == 0) + { + left_shift_limb(result, s); + } +#endif + else + { + left_shift_generic(result, s); + } + // + // We may have shifted off the end and have leading zeros: + // + result.normalize(); +} - limb_type offset = static_cast<limb_type>(s / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits); - limb_type shift = static_cast<limb_type>(s % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits); +template <class Int> +inline void right_shift_byte(Int& result, double_limb_type s) +{ + limb_type offset = static_cast<limb_type>(s / Int::limb_bits); + limb_type shift; + BOOST_ASSERT((s % CHAR_BIT) == 0); unsigned ors = result.size(); unsigned rs = ors; if(offset >= rs) { - if(is_neg) - result = signed_limb_type(-1); - else - result = limb_type(0); + result = limb_type(0); return; } rs -= offset; - typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs(); - if((pr[ors - 1] >> shift) == 0) - --rs; - if(rs == 0) + typename Int::limb_pointer pr = result.limbs(); + unsigned char* pc = reinterpret_cast<unsigned char*>(pr); + shift = static_cast<limb_type>(s / CHAR_BIT); + std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift); + shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT; + if(shift < Int::limb_bits) { - if(is_neg) - result = signed_limb_type(-1); - else - result = limb_type(0); + pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1; + if(!pr[ors - offset - 1] && (rs > 1)) + --rs; + } + result.resize(rs, rs); +} + +template <class Int> +inline void right_shift_limb(Int& result, double_limb_type s) +{ + limb_type offset = static_cast<limb_type>(s / Int::limb_bits); + BOOST_ASSERT((s % Int::limb_bits) == 0); + unsigned ors = result.size(); + unsigned rs = ors; + if(offset >= rs) + { + result = limb_type(0); return; } + rs -= offset; + typename Int::limb_pointer pr = result.limbs(); unsigned i = 0; - if(shift) + for(; i < rs; ++i) + pr[i] = pr[i + offset]; + result.resize(rs, rs); +} + +template <class Int> +inline void right_shift_generic(Int& result, double_limb_type s) +{ + limb_type offset = static_cast<limb_type>(s / Int::limb_bits); + limb_type shift = static_cast<limb_type>(s % Int::limb_bits); + unsigned ors = result.size(); + unsigned rs = ors; + if(offset >= rs) + { + result = limb_type(0); + return; + } + rs -= offset; + typename Int::limb_pointer pr = result.limbs(); + if((pr[ors - 1] >> shift) == 0) { - // This code only works for non-zero shift, otherwise we invoke undefined behaviour! - for(; i + offset + 1 < ors; ++i) + if(--rs == 0) { - pr[i] = pr[i + offset] >> shift; - pr[i] |= pr[i + offset + 1] << (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift); + result = limb_type(0); + return; } - pr[i] = pr[i + offset] >> shift; } - else + unsigned i = 0; + + // This code only works for non-zero shift, otherwise we invoke undefined behaviour! + BOOST_ASSERT(shift); + for(; i + offset + 1 < ors; ++i) { - for(; i < rs; ++i) - pr[i] = pr[i + offset]; + pr[i] = pr[i + offset] >> shift; + pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift); } + pr[i] = pr[i + offset] >> shift; result.resize(rs, rs); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1> +inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type + eval_right_shift( + cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result, + double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value)) +{ + is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type()); + if(!s) + return; + +#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT) + static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1; + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & limb_shift_mask) == 0) + right_shift_limb(result, s); + else if((s & byte_shift_mask) == 0) + right_shift_byte(result, s); +#elif defined(BOOST_LITTLE_ENDIAN) + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & byte_shift_mask) == 0) + right_shift_byte(result, s); +#else + static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1; + if((s & limb_shift_mask) == 0) + right_shift_limb(result, s); +#endif + else + right_shift_generic(result, s); +} +template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1> +inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type + eval_right_shift( + cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, + double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value)) +{ + is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type()); + if(!s) + return; + + bool is_neg = result.sign(); + if(is_neg) + eval_increment(result); + +#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT) + static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1; + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & limb_shift_mask) == 0) + right_shift_limb(result, s); + else if((s & byte_shift_mask) == 0) + right_shift_byte(result, s); +#elif defined(BOOST_LITTLE_ENDIAN) + static const limb_type byte_shift_mask = CHAR_BIT - 1; + if((s & byte_shift_mask) == 0) + right_shift_byte(result, s); +#else + static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1; + if((s & limb_shift_mask) == 0) + right_shift_limb(result, s); +#endif + else + right_shift_generic(result, s); if(is_neg) eval_decrement(result); } @@ -460,7 +636,9 @@ BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBi { // Nothing to check here... just make sure we don't invoke undefined behavior: is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); - *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : *result.limbs() >> s; + *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s); + if(result.sign() && (*result.limbs() == 0)) + result = static_cast<signed_limb_type>(-1); } template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> @@ -469,34 +647,40 @@ inline typename enable_if_c< && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value) >::type - eval_bitwise_and( + eval_complement( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) { - is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); - - using default_ops::eval_bit_test; - using default_ops::eval_increment; - - if(result.sign() || o.sign()) + BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior."); + // + // If we're not checked then emulate 2's complement behavior: + // + if(o.sign()) { - static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value; - cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result); - cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o); - eval_bitwise_and(t1, t2); - bool s = eval_bit_test(t1, m + 1); - if(s) - { - eval_complement(t1, t1); - eval_increment(t1); - } - result = t1; - result.sign(s); + *result.limbs() = *o.limbs() - 1; + result.sign(false); } else { - *result.limbs() &= *o.limbs(); + *result.limbs() = 1 + *o.limbs(); + result.sign(true); } + result.normalize(); +} + +template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> +inline typename enable_if_c< + is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value + && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value + && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value + && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value + >::type + eval_complement( + cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, + const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) +{ + *result.limbs() = ~*o.limbs(); + result.normalize(); } template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> @@ -519,7 +703,7 @@ inline typename enable_if_c< && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value) >::type - eval_bitwise_or( + eval_bitwise_and( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) { @@ -533,7 +717,7 @@ inline typename enable_if_c< static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value; cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result); cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o); - eval_bitwise_or(t1, t2); + eval_bitwise_and(t1, t2); bool s = eval_bit_test(t1, m + 1); if(s) { @@ -545,8 +729,7 @@ inline typename enable_if_c< } else { - *result.limbs() |= *o.limbs(); - result.normalize(); + *result.limbs() &= *o.limbs(); } } @@ -570,7 +753,7 @@ inline typename enable_if_c< && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value) >::type - eval_bitwise_xor( + eval_bitwise_or( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) { @@ -584,7 +767,7 @@ inline typename enable_if_c< static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value; cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result); cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o); - eval_bitwise_xor(t1, t2); + eval_bitwise_or(t1, t2); bool s = eval_bit_test(t1, m + 1); if(s) { @@ -596,7 +779,8 @@ inline typename enable_if_c< } else { - *result.limbs() ^= *o.limbs(); + *result.limbs() |= *o.limbs(); + result.normalize(); } } @@ -620,40 +804,34 @@ inline typename enable_if_c< && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value) >::type - eval_complement( + eval_bitwise_xor( cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) { - BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior."); - // - // If we're not checked then emulate 2's complement behavior: - // - if(o.sign()) + is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type()); + + using default_ops::eval_bit_test; + using default_ops::eval_increment; + + if(result.sign() || o.sign()) { - *result.limbs() = *o.limbs() - 1; - result.sign(false); + static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value; + cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result); + cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o); + eval_bitwise_xor(t1, t2); + bool s = eval_bit_test(t1, m + 1); + if(s) + { + eval_complement(t1, t1); + eval_increment(t1); + } + result = t1; + result.sign(s); } else { - *result.limbs() = 1 + *o.limbs(); - result.sign(true); + *result.limbs() ^= *o.limbs(); } - result.normalize(); -} - -template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2> -inline typename enable_if_c< - is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value - && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value - && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value - && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value - >::type - eval_complement( - cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, - const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)) -{ - *result.limbs() = ~*o.limbs(); - result.normalize(); } }}} // namespaces |