summaryrefslogtreecommitdiff
path: root/boost/multiprecision/cpp_int/bitwise.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/multiprecision/cpp_int/bitwise.hpp')
-rw-r--r--boost/multiprecision/cpp_int/bitwise.hpp426
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