annotate DEPENDENCIES/generic/include/boost/multiprecision/cpp_int/bitwise.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 ///////////////////////////////////////////////////////////////
Chris@16 2 // Copyright 2012 John Maddock. Distributed under the Boost
Chris@16 3 // Software License, Version 1.0. (See accompanying file
Chris@16 4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
Chris@16 5 //
Chris@16 6 // Comparison operators for cpp_int_backend:
Chris@16 7 //
Chris@16 8 #ifndef BOOST_MP_CPP_INT_BIT_HPP
Chris@16 9 #define BOOST_MP_CPP_INT_BIT_HPP
Chris@16 10
Chris@16 11 namespace boost{ namespace multiprecision{ namespace backends{
Chris@16 12
Chris@16 13 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>
Chris@16 14 void is_valid_bitwise_op(
Chris@16 15 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 16 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::int_<checked>&)
Chris@16 17 {
Chris@16 18 if(result.sign() || o.sign())
Chris@16 19 BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
Chris@16 20 }
Chris@16 21
Chris@16 22 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>
Chris@16 23 void is_valid_bitwise_op(
Chris@16 24 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
Chris@16 25 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& , const mpl::int_<unchecked>&){}
Chris@16 26
Chris@16 27 template <class CppInt1, class CppInt2, class Op>
Chris@16 28 void bitwise_op(
Chris@16 29 CppInt1& result,
Chris@16 30 const CppInt2& o,
Chris@101 31 Op op, const mpl::true_&) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
Chris@16 32 {
Chris@16 33 //
Chris@16 34 // There are 4 cases:
Chris@16 35 // * Both positive.
Chris@16 36 // * result negative, o positive.
Chris@16 37 // * o negative, result positive.
Chris@16 38 // * Both negative.
Chris@16 39 //
Chris@16 40 // When one arg is negative we convert to 2's complement form "on the fly",
Chris@16 41 // and then convert back to signed-magnitude form at the end.
Chris@16 42 //
Chris@16 43 // Note however, that if the type is checked, then bitwise ops on negative values
Chris@16 44 // are not permitted and an exception will result.
Chris@16 45 //
Chris@16 46 is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
Chris@16 47 //
Chris@16 48 // First figure out how big the result needs to be and set up some data:
Chris@16 49 //
Chris@16 50 unsigned rs = result.size();
Chris@16 51 unsigned os = o.size();
Chris@16 52 unsigned m, x;
Chris@16 53 minmax(rs, os, m, x);
Chris@16 54 result.resize(x, x);
Chris@16 55 typename CppInt1::limb_pointer pr = result.limbs();
Chris@16 56 typename CppInt2::const_limb_pointer po = o.limbs();
Chris@16 57 for(unsigned i = rs; i < x; ++i)
Chris@16 58 pr[i] = 0;
Chris@16 59
Chris@16 60 limb_type next_limb = 0;
Chris@16 61
Chris@16 62 if(!result.sign())
Chris@16 63 {
Chris@16 64 if(!o.sign())
Chris@16 65 {
Chris@16 66 for(unsigned i = 0; i < os; ++i)
Chris@16 67 pr[i] = op(pr[i], po[i]);
Chris@16 68 for(unsigned i = os; i < x; ++i)
Chris@16 69 pr[i] = op(pr[i], limb_type(0));
Chris@16 70 }
Chris@16 71 else
Chris@16 72 {
Chris@16 73 // "o" is negative:
Chris@16 74 double_limb_type carry = 1;
Chris@16 75 for(unsigned i = 0; i < os; ++i)
Chris@16 76 {
Chris@16 77 carry += static_cast<double_limb_type>(~po[i]);
Chris@16 78 pr[i] = op(pr[i], static_cast<limb_type>(carry));
Chris@16 79 carry >>= CppInt1::limb_bits;
Chris@16 80 }
Chris@16 81 for(unsigned i = os; i < x; ++i)
Chris@16 82 {
Chris@16 83 carry += static_cast<double_limb_type>(~limb_type(0));
Chris@16 84 pr[i] = op(pr[i], static_cast<limb_type>(carry));
Chris@16 85 carry >>= CppInt1::limb_bits;
Chris@16 86 }
Chris@16 87 // Set the overflow into the "extra" limb:
Chris@16 88 carry += static_cast<double_limb_type>(~limb_type(0));
Chris@16 89 next_limb = op(limb_type(0), static_cast<limb_type>(carry));
Chris@16 90 }
Chris@16 91 }
Chris@16 92 else
Chris@16 93 {
Chris@16 94 if(!o.sign())
Chris@16 95 {
Chris@16 96 // "result" is negative:
Chris@16 97 double_limb_type carry = 1;
Chris@16 98 for(unsigned i = 0; i < os; ++i)
Chris@16 99 {
Chris@16 100 carry += static_cast<double_limb_type>(~pr[i]);
Chris@16 101 pr[i] = op(static_cast<limb_type>(carry), po[i]);
Chris@16 102 carry >>= CppInt1::limb_bits;
Chris@16 103 }
Chris@16 104 for(unsigned i = os; i < x; ++i)
Chris@16 105 {
Chris@16 106 carry += static_cast<double_limb_type>(~pr[i]);
Chris@16 107 pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
Chris@16 108 carry >>= CppInt1::limb_bits;
Chris@16 109 }
Chris@16 110 // Set the overflow into the "extra" limb:
Chris@16 111 carry += static_cast<double_limb_type>(~limb_type(0));
Chris@16 112 next_limb = op(static_cast<limb_type>(carry), limb_type(0));
Chris@16 113 }
Chris@16 114 else
Chris@16 115 {
Chris@16 116 // both are negative:
Chris@16 117 double_limb_type r_carry = 1;
Chris@16 118 double_limb_type o_carry = 1;
Chris@16 119 for(unsigned i = 0; i < os; ++i)
Chris@16 120 {
Chris@16 121 r_carry += static_cast<double_limb_type>(~pr[i]);
Chris@16 122 o_carry += static_cast<double_limb_type>(~po[i]);
Chris@16 123 pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
Chris@16 124 r_carry >>= CppInt1::limb_bits;
Chris@16 125 o_carry >>= CppInt1::limb_bits;
Chris@16 126 }
Chris@16 127 for(unsigned i = os; i < x; ++i)
Chris@16 128 {
Chris@16 129 r_carry += static_cast<double_limb_type>(~pr[i]);
Chris@16 130 o_carry += static_cast<double_limb_type>(~limb_type(0));
Chris@16 131 pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
Chris@16 132 r_carry >>= CppInt1::limb_bits;
Chris@16 133 o_carry >>= CppInt1::limb_bits;
Chris@16 134 }
Chris@16 135 // Set the overflow into the "extra" limb:
Chris@16 136 r_carry += static_cast<double_limb_type>(~limb_type(0));
Chris@16 137 o_carry += static_cast<double_limb_type>(~limb_type(0));
Chris@16 138 next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
Chris@16 139 }
Chris@16 140 }
Chris@16 141 //
Chris@16 142 // See if the result is negative or not:
Chris@16 143 //
Chris@16 144 if(static_cast<signed_limb_type>(next_limb) < 0)
Chris@16 145 {
Chris@16 146 result.sign(true);
Chris@16 147 double_limb_type carry = 1;
Chris@16 148 for(unsigned i = 0; i < x; ++i)
Chris@16 149 {
Chris@16 150 carry += static_cast<double_limb_type>(~pr[i]);
Chris@16 151 pr[i] = static_cast<limb_type>(carry);
Chris@16 152 carry >>= CppInt1::limb_bits;
Chris@16 153 }
Chris@16 154 }
Chris@16 155 else
Chris@16 156 result.sign(false);
Chris@16 157
Chris@16 158 result.normalize();
Chris@16 159 }
Chris@16 160
Chris@101 161 template <class CppInt1, class CppInt2, class Op>
Chris@101 162 void bitwise_op(
Chris@101 163 CppInt1& result,
Chris@101 164 const CppInt2& o,
Chris@101 165 Op op, const mpl::false_&) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
Chris@101 166 {
Chris@101 167 //
Chris@101 168 // Both arguments are unsigned types, very simple case handled as a special case.
Chris@101 169 //
Chris@101 170 // First figure out how big the result needs to be and set up some data:
Chris@101 171 //
Chris@101 172 unsigned rs = result.size();
Chris@101 173 unsigned os = o.size();
Chris@101 174 unsigned m, x;
Chris@101 175 minmax(rs, os, m, x);
Chris@101 176 result.resize(x, x);
Chris@101 177 typename CppInt1::limb_pointer pr = result.limbs();
Chris@101 178 typename CppInt2::const_limb_pointer po = o.limbs();
Chris@101 179 for(unsigned i = rs; i < x; ++i)
Chris@101 180 pr[i] = 0;
Chris@101 181
Chris@101 182 for(unsigned i = 0; i < os; ++i)
Chris@101 183 pr[i] = op(pr[i], po[i]);
Chris@101 184 for(unsigned i = os; i < x; ++i)
Chris@101 185 pr[i] = op(pr[i], limb_type(0));
Chris@101 186
Chris@101 187 result.normalize();
Chris@101 188 }
Chris@101 189
Chris@16 190 struct bit_and{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a & b; } };
Chris@16 191 struct bit_or { limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a | b; } };
Chris@16 192 struct bit_xor{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a ^ b; } };
Chris@16 193
Chris@16 194 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>
Chris@16 195 BOOST_MP_FORCEINLINE 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 >::type
Chris@16 196 eval_bitwise_and(
Chris@16 197 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 198 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 199 {
Chris@101 200 bitwise_op(result, o, bit_and(),
Chris@101 201 mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
Chris@16 202 }
Chris@16 203
Chris@16 204 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>
Chris@16 205 BOOST_MP_FORCEINLINE 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 >::type
Chris@16 206 eval_bitwise_or(
Chris@16 207 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 208 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 209 {
Chris@101 210 bitwise_op(result, o, bit_or(),
Chris@101 211 mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
Chris@16 212 }
Chris@16 213
Chris@16 214 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>
Chris@16 215 BOOST_MP_FORCEINLINE 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 >::type
Chris@16 216 eval_bitwise_xor(
Chris@16 217 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 218 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 219 {
Chris@101 220 bitwise_op(result, o, bit_xor(),
Chris@101 221 mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
Chris@101 222 }
Chris@101 223 //
Chris@101 224 // Again for operands which are single limbs:
Chris@101 225 //
Chris@101 226 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
Chris@101 227 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
Chris@101 228 eval_bitwise_and(
Chris@101 229 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
Chris@101 230 limb_type l) BOOST_NOEXCEPT
Chris@101 231 {
Chris@101 232 result.limbs()[0] &= l;
Chris@101 233 result.resize(1, 1);
Chris@101 234 }
Chris@101 235
Chris@101 236 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
Chris@101 237 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
Chris@101 238 eval_bitwise_or(
Chris@101 239 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
Chris@101 240 limb_type l) BOOST_NOEXCEPT
Chris@101 241 {
Chris@101 242 result.limbs()[0] |= l;
Chris@101 243 }
Chris@101 244
Chris@101 245 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
Chris@101 246 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
Chris@101 247 eval_bitwise_xor(
Chris@101 248 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
Chris@101 249 limb_type l) BOOST_NOEXCEPT
Chris@101 250 {
Chris@101 251 result.limbs()[0] ^= l;
Chris@16 252 }
Chris@16 253
Chris@16 254 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>
Chris@16 255 BOOST_MP_FORCEINLINE typename enable_if_c<is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !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 >::type
Chris@16 256 eval_complement(
Chris@16 257 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 258 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 259 {
Chris@16 260 BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
Chris@16 261 // Increment and negate:
Chris@16 262 result = o;
Chris@16 263 eval_increment(result);
Chris@16 264 result.negate();
Chris@16 265 }
Chris@16 266
Chris@16 267 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 268 BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
Chris@16 269 eval_complement(
Chris@16 270 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 271 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 272 {
Chris@16 273 unsigned os = o.size();
Chris@16 274 result.resize(UINT_MAX, os);
Chris@16 275 for(unsigned i = 0; i < os; ++i)
Chris@16 276 result.limbs()[i] = ~o.limbs()[i];
Chris@16 277 for(unsigned i = os; i < result.size(); ++i)
Chris@16 278 result.limbs()[i] = ~static_cast<limb_type>(0);
Chris@16 279 result.normalize();
Chris@16 280 }
Chris@16 281
Chris@16 282 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 283 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 284 eval_left_shift(
Chris@16 285 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 286 double_limb_type s) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 287 {
Chris@16 288 if(!s)
Chris@16 289 return;
Chris@16 290
Chris@16 291 limb_type offset = static_cast<limb_type>(s / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
Chris@16 292 limb_type shift = static_cast<limb_type>(s % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
Chris@16 293
Chris@16 294 unsigned ors = result.size();
Chris@16 295 if((ors == 1) && (!*result.limbs()))
Chris@16 296 return; // shifting zero yields zero.
Chris@16 297 unsigned rs = ors;
Chris@16 298 if(shift && (result.limbs()[ors - 1] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift)))
Chris@16 299 ++rs; // Most significant limb will overflow when shifted
Chris@16 300 rs += offset;
Chris@16 301 result.resize(rs, rs);
Chris@16 302 bool truncated = result.size() != rs;
Chris@16 303
Chris@16 304 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
Chris@16 305
Chris@16 306 if(offset > rs)
Chris@16 307 {
Chris@16 308 // The result is shifted past the end of the result:
Chris@16 309 result = static_cast<limb_type>(0);
Chris@16 310 return;
Chris@16 311 }
Chris@16 312
Chris@16 313 unsigned i = rs - result.size();
Chris@16 314 if(shift)
Chris@16 315 {
Chris@16 316 // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
Chris@16 317 if(!truncated)
Chris@16 318 {
Chris@16 319 if(rs > ors + offset)
Chris@16 320 {
Chris@16 321 pr[rs - 1 - i] = pr[ors - 1 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
Chris@16 322 --rs;
Chris@16 323 }
Chris@16 324 else
Chris@16 325 {
Chris@16 326 pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
Chris@16 327 if(ors > 1)
Chris@16 328 pr[rs - 1 - i] |= pr[ors - 2 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
Chris@16 329 ++i;
Chris@16 330 }
Chris@16 331 }
Chris@16 332 for(; ors > 1 + i; ++i)
Chris@16 333 {
Chris@16 334 pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
Chris@16 335 pr[rs - 1 - i] |= pr[ors - 2 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
Chris@16 336 }
Chris@16 337 if(ors >= 1 + i)
Chris@16 338 {
Chris@16 339 pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
Chris@16 340 ++i;
Chris@16 341 }
Chris@16 342 for(; i < rs; ++i)
Chris@16 343 pr[rs - 1 - i] = 0;
Chris@16 344 }
Chris@16 345 else
Chris@16 346 {
Chris@16 347 for(; i < ors; ++i)
Chris@16 348 pr[rs - 1 - i] = pr[ors - 1 - i];
Chris@16 349 for(; i < rs; ++i)
Chris@16 350 pr[rs - 1 - i] = 0;
Chris@16 351 }
Chris@16 352 //
Chris@16 353 // We may have shifted off the end and have leading zeros:
Chris@16 354 //
Chris@16 355 result.normalize();
Chris@16 356 }
Chris@16 357
Chris@16 358 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 359 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 360 eval_right_shift(
Chris@16 361 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 362 double_limb_type s) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 363 {
Chris@16 364 if(!s)
Chris@16 365 return;
Chris@16 366
Chris@16 367 limb_type offset = static_cast<limb_type>(s / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
Chris@16 368 limb_type shift = static_cast<limb_type>(s % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
Chris@16 369 unsigned ors = result.size();
Chris@16 370 unsigned rs = ors;
Chris@16 371 if(offset >= rs)
Chris@16 372 {
Chris@16 373 result = limb_type(0);
Chris@16 374 return;
Chris@16 375 }
Chris@16 376 rs -= offset;
Chris@16 377 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
Chris@16 378 if((pr[ors - 1] >> shift) == 0)
Chris@16 379 --rs;
Chris@16 380 if(rs == 0)
Chris@16 381 {
Chris@16 382 result = limb_type(0);
Chris@16 383 return;
Chris@16 384 }
Chris@16 385 unsigned i = 0;
Chris@16 386 if(shift)
Chris@16 387 {
Chris@16 388 // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
Chris@16 389 for(; i + offset + 1 < ors; ++i)
Chris@16 390 {
Chris@16 391 pr[i] = pr[i + offset] >> shift;
Chris@16 392 pr[i] |= pr[i + offset + 1] << (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
Chris@16 393 }
Chris@16 394 pr[i] = pr[i + offset] >> shift;
Chris@16 395 }
Chris@16 396 else
Chris@16 397 {
Chris@16 398 for(; i < rs; ++i)
Chris@16 399 pr[i] = pr[i + offset];
Chris@16 400 }
Chris@16 401 result.resize(rs, rs);
Chris@16 402 }
Chris@16 403
Chris@16 404 //
Chris@16 405 // Over again for trivial cpp_int's:
Chris@16 406 //
Chris@16 407 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
Chris@16 408 BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
Chris@16 409 eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 410 {
Chris@16 411 *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
Chris@16 412 result.normalize();
Chris@16 413 }
Chris@16 414
Chris@16 415 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
Chris@16 416 BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
Chris@16 417 eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 418 {
Chris@16 419 // Nothing to check here... just make sure we don't invoke undefined behavior:
Chris@16 420 *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : *result.limbs() >> s;
Chris@16 421 }
Chris@16 422
Chris@16 423 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>
Chris@16 424 inline typename enable_if_c<
Chris@16 425 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 426 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 427 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
Chris@16 428 >::type
Chris@16 429 eval_bitwise_and(
Chris@16 430 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 431 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 432 {
Chris@16 433 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
Chris@16 434
Chris@16 435 using default_ops::eval_bit_test;
Chris@16 436 using default_ops::eval_increment;
Chris@16 437
Chris@16 438 if(result.sign() || o.sign())
Chris@16 439 {
Chris@16 440 static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
Chris@16 441 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
Chris@16 442 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
Chris@16 443 eval_bitwise_and(t1, t2);
Chris@16 444 bool s = eval_bit_test(t1, m + 1);
Chris@16 445 if(s)
Chris@16 446 {
Chris@16 447 eval_complement(t1, t1);
Chris@16 448 eval_increment(t1);
Chris@16 449 }
Chris@16 450 result = t1;
Chris@16 451 result.sign(s);
Chris@16 452 }
Chris@16 453 else
Chris@16 454 {
Chris@16 455 *result.limbs() &= *o.limbs();
Chris@16 456 }
Chris@16 457 }
Chris@16 458
Chris@16 459 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>
Chris@16 460 inline typename enable_if_c<
Chris@16 461 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 462 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 463 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 464 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 465 >::type
Chris@16 466 eval_bitwise_and(
Chris@16 467 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 468 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 469 {
Chris@16 470 *result.limbs() &= *o.limbs();
Chris@16 471 }
Chris@16 472
Chris@16 473 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>
Chris@16 474 inline typename enable_if_c<
Chris@16 475 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 476 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 477 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
Chris@16 478 >::type
Chris@16 479 eval_bitwise_or(
Chris@16 480 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 481 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 482 {
Chris@16 483 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
Chris@16 484
Chris@16 485 using default_ops::eval_bit_test;
Chris@16 486 using default_ops::eval_increment;
Chris@16 487
Chris@16 488 if(result.sign() || o.sign())
Chris@16 489 {
Chris@16 490 static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
Chris@16 491 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
Chris@16 492 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
Chris@16 493 eval_bitwise_or(t1, t2);
Chris@16 494 bool s = eval_bit_test(t1, m + 1);
Chris@16 495 if(s)
Chris@16 496 {
Chris@16 497 eval_complement(t1, t1);
Chris@16 498 eval_increment(t1);
Chris@16 499 }
Chris@16 500 result = t1;
Chris@16 501 result.sign(s);
Chris@16 502 }
Chris@16 503 else
Chris@16 504 {
Chris@16 505 *result.limbs() |= *o.limbs();
Chris@16 506 result.normalize();
Chris@16 507 }
Chris@16 508 }
Chris@16 509
Chris@16 510 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>
Chris@16 511 inline typename enable_if_c<
Chris@16 512 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 513 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 514 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 515 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 516 >::type
Chris@16 517 eval_bitwise_or(
Chris@16 518 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 519 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 520 {
Chris@16 521 *result.limbs() |= *o.limbs();
Chris@16 522 }
Chris@16 523
Chris@16 524 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>
Chris@16 525 inline typename enable_if_c<
Chris@16 526 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 527 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 528 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
Chris@16 529 >::type
Chris@16 530 eval_bitwise_xor(
Chris@16 531 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 532 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 533 {
Chris@16 534 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
Chris@16 535
Chris@16 536 using default_ops::eval_bit_test;
Chris@16 537 using default_ops::eval_increment;
Chris@16 538
Chris@16 539 if(result.sign() || o.sign())
Chris@16 540 {
Chris@16 541 static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
Chris@16 542 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
Chris@16 543 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
Chris@16 544 eval_bitwise_xor(t1, t2);
Chris@16 545 bool s = eval_bit_test(t1, m + 1);
Chris@16 546 if(s)
Chris@16 547 {
Chris@16 548 eval_complement(t1, t1);
Chris@16 549 eval_increment(t1);
Chris@16 550 }
Chris@16 551 result = t1;
Chris@16 552 result.sign(s);
Chris@16 553 }
Chris@16 554 else
Chris@16 555 {
Chris@16 556 *result.limbs() ^= *o.limbs();
Chris@16 557 }
Chris@16 558 }
Chris@16 559
Chris@16 560 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>
Chris@16 561 inline typename enable_if_c<
Chris@16 562 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 563 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 564 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 565 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 566 >::type
Chris@16 567 eval_bitwise_xor(
Chris@16 568 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 569 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 570 {
Chris@16 571 *result.limbs() ^= *o.limbs();
Chris@16 572 }
Chris@16 573
Chris@16 574 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>
Chris@16 575 inline typename enable_if_c<
Chris@16 576 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 577 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 578 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
Chris@16 579 >::type
Chris@16 580 eval_complement(
Chris@16 581 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 582 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 583 {
Chris@16 584 BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
Chris@16 585 //
Chris@16 586 // If we're not checked then emulate 2's complement behavior:
Chris@16 587 //
Chris@16 588 if(o.sign())
Chris@16 589 {
Chris@16 590 *result.limbs() = *o.limbs() - 1;
Chris@16 591 result.sign(false);
Chris@16 592 }
Chris@16 593 else
Chris@16 594 {
Chris@16 595 *result.limbs() = 1 + *o.limbs();
Chris@16 596 result.sign(true);
Chris@16 597 }
Chris@16 598 result.normalize();
Chris@16 599 }
Chris@16 600
Chris@16 601 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>
Chris@16 602 inline typename enable_if_c<
Chris@16 603 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 604 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 605 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 606 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
Chris@16 607 >::type
Chris@16 608 eval_complement(
Chris@16 609 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 610 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 611 {
Chris@16 612 *result.limbs() = ~*o.limbs();
Chris@16 613 result.normalize();
Chris@16 614 }
Chris@16 615
Chris@16 616 }}} // namespaces
Chris@16 617
Chris@16 618 #endif