annotate DEPENDENCIES/generic/include/boost/multiprecision/cpp_int/misc.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_MISC_HPP
Chris@16 9 #define BOOST_MP_CPP_INT_MISC_HPP
Chris@16 10
Chris@16 11 #include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
Chris@101 12 #include <boost/integer/common_factor_rt.hpp> // gcd/lcm
Chris@16 13
Chris@16 14 #ifdef BOOST_MSVC
Chris@16 15 #pragma warning(push)
Chris@16 16 #pragma warning(disable:4702)
Chris@16 17 #endif
Chris@16 18
Chris@16 19 namespace boost{ namespace multiprecision{ namespace backends{
Chris@16 20
Chris@16 21 template <class R, class CppInt>
Chris@16 22 void check_in_range(const CppInt& val, const mpl::int_<checked>&)
Chris@16 23 {
Chris@16 24 typedef typename boost::multiprecision::detail::canonical<R, CppInt>::type cast_type;
Chris@16 25 if(val.sign())
Chris@16 26 {
Chris@16 27 if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::min)())) < 0)
Chris@16 28 BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
Chris@16 29 }
Chris@16 30 else
Chris@16 31 {
Chris@16 32 if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::max)())) > 0)
Chris@16 33 BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
Chris@16 34 }
Chris@16 35 }
Chris@16 36 template <class R, class CppInt>
Chris@16 37 inline void check_in_range(const CppInt& /*val*/, const mpl::int_<unchecked>&) BOOST_NOEXCEPT {}
Chris@16 38
Chris@16 39 inline void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {}
Chris@16 40 inline void check_is_negative(const mpl::false_&)
Chris@16 41 {
Chris@16 42 BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
Chris@16 43 }
Chris@16 44
Chris@16 45 template <class Integer>
Chris@16 46 inline Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT
Chris@16 47 {
Chris@16 48 return -i;
Chris@16 49 }
Chris@16 50 template <class Integer>
Chris@16 51 inline Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT
Chris@16 52 {
Chris@16 53 return ~(i-1);
Chris@16 54 }
Chris@16 55
Chris@16 56 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 57 inline typename enable_if_c<is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
Chris@16 58 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 59 {
Chris@16 60 typedef mpl::int_<Checked1> checked_type;
Chris@16 61 check_in_range<R>(backend, checked_type());
Chris@16 62
Chris@16 63 *result = static_cast<R>(backend.limbs()[0]);
Chris@16 64 unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 65 for(unsigned i = 1; (i < backend.size()) && (shift < static_cast<unsigned>(std::numeric_limits<R>::digits)); ++i)
Chris@16 66 {
Chris@16 67 *result += static_cast<R>(backend.limbs()[i]) << shift;
Chris@16 68 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 69 }
Chris@16 70 if(backend.sign())
Chris@16 71 {
Chris@16 72 check_is_negative(boost::is_signed<R>());
Chris@16 73 *result = negate_integer(*result, boost::is_signed<R>());
Chris@16 74 }
Chris@16 75 }
Chris@16 76
Chris@16 77 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 78 inline typename enable_if_c<is_floating_point<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
Chris@16 79 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_NOEXCEPT_IF(is_arithmetic<R>::value)
Chris@16 80 {
Chris@16 81 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
Chris@16 82 unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 83 *result = static_cast<R>(*p);
Chris@16 84 for(unsigned i = 1; i < backend.size(); ++i)
Chris@16 85 {
Chris@16 86 *result += static_cast<R>(std::ldexp(static_cast<long double>(p[i]), shift));
Chris@16 87 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 88 }
Chris@16 89 if(backend.sign())
Chris@16 90 *result = -*result;
Chris@16 91 }
Chris@16 92
Chris@16 93 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 94 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
Chris@16 95 eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
Chris@16 96 {
Chris@16 97 return (val.size() == 1) && (val.limbs()[0] == 0);
Chris@16 98 }
Chris@16 99 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 100 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
Chris@16 101 eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
Chris@16 102 {
Chris@16 103 return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
Chris@16 104 }
Chris@16 105 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 106 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 107 eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 108 {
Chris@16 109 result = val;
Chris@16 110 result.sign(false);
Chris@16 111 }
Chris@16 112
Chris@16 113 //
Chris@16 114 // Get the location of the least-significant-bit:
Chris@16 115 //
Chris@16 116 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 117 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
Chris@16 118 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
Chris@16 119 {
Chris@16 120 using default_ops::eval_get_sign;
Chris@16 121 if(eval_get_sign(a) == 0)
Chris@16 122 {
Chris@16 123 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
Chris@16 124 }
Chris@16 125 if(a.sign())
Chris@16 126 {
Chris@16 127 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
Chris@16 128 }
Chris@16 129
Chris@16 130 //
Chris@16 131 // Find the index of the least significant limb that is non-zero:
Chris@16 132 //
Chris@16 133 unsigned index = 0;
Chris@16 134 while(!a.limbs()[index] && (index < a.size()))
Chris@16 135 ++index;
Chris@16 136 //
Chris@16 137 // Find the index of the least significant bit within that limb:
Chris@16 138 //
Chris@16 139 unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
Chris@16 140
Chris@16 141 return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 142 }
Chris@16 143
Chris@16 144 //
Chris@16 145 // Get the location of the most-significant-bit:
Chris@16 146 //
Chris@16 147 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 148 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
Chris@16 149 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
Chris@16 150 {
Chris@16 151 using default_ops::eval_get_sign;
Chris@16 152 if(eval_get_sign(a) == 0)
Chris@16 153 {
Chris@16 154 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
Chris@16 155 }
Chris@16 156 if(a.sign())
Chris@16 157 {
Chris@16 158 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
Chris@16 159 }
Chris@16 160
Chris@16 161 //
Chris@16 162 // Find the index of the most significant bit that is non-zero:
Chris@16 163 //
Chris@16 164 return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
Chris@16 165 }
Chris@16 166
Chris@16 167 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 168 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
Chris@16 169 eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
Chris@16 170 {
Chris@16 171 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 172 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 173 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
Chris@16 174 if(offset >= val.size())
Chris@16 175 return false;
Chris@16 176 return val.limbs()[offset] & mask ? true : false;
Chris@16 177 }
Chris@16 178
Chris@16 179 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 180 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 181 eval_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
Chris@16 182 {
Chris@16 183 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 184 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 185 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
Chris@16 186 if(offset >= val.size())
Chris@16 187 {
Chris@16 188 unsigned os = val.size();
Chris@16 189 val.resize(offset + 1, offset + 1);
Chris@16 190 if(offset >= val.size())
Chris@16 191 return; // fixed precision overflow
Chris@16 192 for(unsigned i = os; i <= offset; ++i)
Chris@16 193 val.limbs()[i] = 0;
Chris@16 194 }
Chris@16 195 val.limbs()[offset] |= mask;
Chris@16 196 }
Chris@16 197
Chris@16 198 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 199 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 200 eval_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
Chris@16 201 {
Chris@16 202 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 203 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 204 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
Chris@16 205 if(offset >= val.size())
Chris@16 206 return;
Chris@16 207 val.limbs()[offset] &= ~mask;
Chris@16 208 val.normalize();
Chris@16 209 }
Chris@16 210
Chris@16 211 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 212 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 213 eval_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
Chris@16 214 {
Chris@16 215 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 216 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
Chris@16 217 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
Chris@16 218 if(offset >= val.size())
Chris@16 219 {
Chris@16 220 unsigned os = val.size();
Chris@16 221 val.resize(offset + 1, offset + 1);
Chris@16 222 if(offset >= val.size())
Chris@16 223 return; // fixed precision overflow
Chris@16 224 for(unsigned i = os; i <= offset; ++i)
Chris@16 225 val.limbs()[i] = 0;
Chris@16 226 }
Chris@16 227 val.limbs()[offset] ^= mask;
Chris@16 228 val.normalize();
Chris@16 229 }
Chris@16 230
Chris@16 231 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 232 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 233 eval_qr(
Chris@16 234 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
Chris@16 235 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
Chris@16 236 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
Chris@16 237 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 238 {
Chris@16 239 divide_unsigned_helper(&q, x, y, r);
Chris@16 240 q.sign(x.sign() != y.sign());
Chris@16 241 r.sign(x.sign());
Chris@16 242 }
Chris@16 243
Chris@101 244 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@101 245 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@101 246 eval_qr(
Chris@101 247 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
Chris@101 248 limb_type y,
Chris@101 249 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
Chris@101 250 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@101 251 {
Chris@101 252 divide_unsigned_helper(&q, x, y, r);
Chris@101 253 q.sign(x.sign());
Chris@101 254 r.sign(x.sign());
Chris@101 255 }
Chris@101 256
Chris@101 257 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
Chris@101 258 inline typename enable_if_c<is_integral<U>::value>::type eval_qr(
Chris@101 259 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
Chris@101 260 U y,
Chris@101 261 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
Chris@101 262 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@101 263 {
Chris@101 264 using default_ops::eval_qr;
Chris@101 265 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(y);
Chris@101 266 eval_qr(x, t, q, r);
Chris@101 267 }
Chris@101 268
Chris@16 269 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
Chris@16 270 inline typename enable_if_c<is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
Chris@16 271 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
Chris@16 272 {
Chris@16 273 if((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits<limb_type>::max)()))
Chris@16 274 {
Chris@16 275 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> d;
Chris@16 276 divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>*>(0), x, static_cast<limb_type>(val), d);
Chris@16 277 return d.limbs()[0];
Chris@16 278 }
Chris@16 279 else
Chris@16 280 {
Chris@16 281 return default_ops::eval_integer_modulus(x, val);
Chris@16 282 }
Chris@16 283 }
Chris@16 284
Chris@16 285 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
Chris@16 286 BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
Chris@16 287 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
Chris@16 288 {
Chris@101 289 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
Chris@16 290 }
Chris@16 291
Chris@16 292 inline limb_type integer_gcd_reduce(limb_type u, limb_type v)
Chris@16 293 {
Chris@16 294 do
Chris@16 295 {
Chris@16 296 if(u > v)
Chris@16 297 std::swap(u, v);
Chris@16 298 if(u == v)
Chris@16 299 break;
Chris@16 300 v -= u;
Chris@16 301 v >>= boost::multiprecision::detail::find_lsb(v);
Chris@16 302 } while(true);
Chris@16 303 return u;
Chris@16 304 }
Chris@16 305
Chris@16 306 inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v)
Chris@16 307 {
Chris@16 308 do
Chris@16 309 {
Chris@16 310 if(u > v)
Chris@16 311 std::swap(u, v);
Chris@16 312 if(u == v)
Chris@16 313 break;
Chris@16 314 if(v <= ~static_cast<limb_type>(0))
Chris@16 315 {
Chris@16 316 u = integer_gcd_reduce(static_cast<limb_type>(v), static_cast<limb_type>(u));
Chris@16 317 break;
Chris@16 318 }
Chris@16 319 v -= u;
Chris@16 320 while((static_cast<unsigned>(v) & 1u) == 0)
Chris@16 321 v >>= 1;
Chris@16 322 } while(true);
Chris@16 323 return u;
Chris@16 324 }
Chris@16 325
Chris@16 326 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 327 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 328 eval_gcd(
Chris@16 329 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 330 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
Chris@16 331 limb_type v)
Chris@16 332 {
Chris@16 333 using default_ops::eval_lsb;
Chris@16 334 using default_ops::eval_is_zero;
Chris@16 335 using default_ops::eval_get_sign;
Chris@16 336
Chris@16 337 int shift;
Chris@16 338
Chris@16 339 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a);
Chris@16 340
Chris@16 341 int s = eval_get_sign(u);
Chris@16 342
Chris@16 343 /* GCD(0,x) := x */
Chris@16 344 if(s < 0)
Chris@16 345 {
Chris@16 346 u.negate();
Chris@16 347 }
Chris@16 348 else if(s == 0)
Chris@16 349 {
Chris@16 350 result = v;
Chris@16 351 return;
Chris@16 352 }
Chris@16 353 if(v == 0)
Chris@16 354 {
Chris@16 355 result = u;
Chris@16 356 return;
Chris@16 357 }
Chris@16 358
Chris@16 359 /* Let shift := lg K, where K is the greatest power of 2
Chris@16 360 dividing both u and v. */
Chris@16 361
Chris@16 362 unsigned us = eval_lsb(u);
Chris@16 363 unsigned vs = boost::multiprecision::detail::find_lsb(v);
Chris@16 364 shift = (std::min)(us, vs);
Chris@16 365 eval_right_shift(u, us);
Chris@16 366 if(vs)
Chris@16 367 v >>= vs;
Chris@16 368
Chris@16 369 do
Chris@16 370 {
Chris@16 371 /* Now u and v are both odd, so diff(u, v) is even.
Chris@16 372 Let u = min(u, v), v = diff(u, v)/2. */
Chris@16 373 if(u.size() <= 2)
Chris@16 374 {
Chris@16 375 if(u.size() == 1)
Chris@16 376 v = integer_gcd_reduce(*u.limbs(), v);
Chris@16 377 else
Chris@16 378 {
Chris@16 379 double_limb_type i;
Chris@16 380 i = u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
Chris@16 381 v = static_cast<limb_type>(integer_gcd_reduce(i, static_cast<double_limb_type>(v)));
Chris@16 382 }
Chris@16 383 break;
Chris@16 384 }
Chris@16 385 eval_subtract(u, v);
Chris@16 386 us = eval_lsb(u);
Chris@16 387 eval_right_shift(u, us);
Chris@16 388 }
Chris@16 389 while(true);
Chris@16 390
Chris@16 391 result = v;
Chris@16 392 eval_left_shift(result, shift);
Chris@16 393 }
Chris@16 394 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
Chris@16 395 inline typename enable_if_c<is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 396 eval_gcd(
Chris@16 397 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 398 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
Chris@16 399 const Integer& v)
Chris@16 400 {
Chris@16 401 eval_gcd(result, a, static_cast<limb_type>(v));
Chris@16 402 }
Chris@16 403 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
Chris@16 404 inline typename enable_if_c<is_signed<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 405 eval_gcd(
Chris@16 406 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 407 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
Chris@16 408 const Integer& v)
Chris@16 409 {
Chris@16 410 eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
Chris@16 411 }
Chris@16 412
Chris@16 413 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 414 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 415 eval_gcd(
Chris@16 416 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
Chris@16 417 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
Chris@16 418 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b)
Chris@16 419 {
Chris@16 420 using default_ops::eval_lsb;
Chris@16 421 using default_ops::eval_is_zero;
Chris@16 422 using default_ops::eval_get_sign;
Chris@16 423
Chris@16 424 if(a.size() == 1)
Chris@16 425 {
Chris@16 426 eval_gcd(result, b, *a.limbs());
Chris@16 427 return;
Chris@16 428 }
Chris@16 429 if(b.size() == 1)
Chris@16 430 {
Chris@16 431 eval_gcd(result, a, *b.limbs());
Chris@16 432 return;
Chris@16 433 }
Chris@16 434
Chris@16 435 int shift;
Chris@16 436
Chris@16 437 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a), v(b);
Chris@16 438
Chris@16 439 int s = eval_get_sign(u);
Chris@16 440
Chris@16 441 /* GCD(0,x) := x */
Chris@16 442 if(s < 0)
Chris@16 443 {
Chris@16 444 u.negate();
Chris@16 445 }
Chris@16 446 else if(s == 0)
Chris@16 447 {
Chris@16 448 result = v;
Chris@16 449 return;
Chris@16 450 }
Chris@16 451 s = eval_get_sign(v);
Chris@16 452 if(s < 0)
Chris@16 453 {
Chris@16 454 v.negate();
Chris@16 455 }
Chris@16 456 else if(s == 0)
Chris@16 457 {
Chris@16 458 result = u;
Chris@16 459 return;
Chris@16 460 }
Chris@16 461
Chris@16 462 /* Let shift := lg K, where K is the greatest power of 2
Chris@16 463 dividing both u and v. */
Chris@16 464
Chris@16 465 unsigned us = eval_lsb(u);
Chris@16 466 unsigned vs = eval_lsb(v);
Chris@16 467 shift = (std::min)(us, vs);
Chris@16 468 eval_right_shift(u, us);
Chris@16 469 eval_right_shift(v, vs);
Chris@16 470
Chris@16 471 do
Chris@16 472 {
Chris@16 473 /* Now u and v are both odd, so diff(u, v) is even.
Chris@16 474 Let u = min(u, v), v = diff(u, v)/2. */
Chris@16 475 s = u.compare(v);
Chris@16 476 if(s > 0)
Chris@16 477 u.swap(v);
Chris@16 478 if(s == 0)
Chris@16 479 break;
Chris@16 480 if(v.size() <= 2)
Chris@16 481 {
Chris@16 482 if(v.size() == 1)
Chris@16 483 u = integer_gcd_reduce(*v.limbs(), *u.limbs());
Chris@16 484 else
Chris@16 485 {
Chris@16 486 double_limb_type i, j;
Chris@16 487 i = v.limbs()[0] | (static_cast<double_limb_type>(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
Chris@16 488 j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
Chris@16 489 u = integer_gcd_reduce(i, j);
Chris@16 490 }
Chris@16 491 break;
Chris@16 492 }
Chris@16 493 eval_subtract(v, u);
Chris@16 494 vs = eval_lsb(v);
Chris@16 495 eval_right_shift(v, vs);
Chris@16 496 }
Chris@16 497 while(true);
Chris@16 498
Chris@16 499 result = u;
Chris@16 500 eval_left_shift(result, shift);
Chris@16 501 }
Chris@16 502 //
Chris@16 503 // Now again for trivial backends:
Chris@16 504 //
Chris@16 505 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 506 BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
Chris@16 507 eval_gcd(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT
Chris@16 508 {
Chris@101 509 *result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs());
Chris@16 510 }
Chris@16 511 // This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version:
Chris@16 512 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 513 BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
Chris@16 514 eval_lcm(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
Chris@16 515 {
Chris@101 516 *result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs());
Chris@16 517 result.normalize(); // result may overflow the specified number of bits
Chris@16 518 }
Chris@16 519
Chris@16 520 inline void conversion_overflow(const mpl::int_<checked>&)
Chris@16 521 {
Chris@16 522 BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
Chris@16 523 }
Chris@16 524 inline void conversion_overflow(const mpl::int_<unchecked>&){}
Chris@16 525
Chris@16 526 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 527 inline typename enable_if_c<
Chris@16 528 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 529 && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 530 >::type
Chris@16 531 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
Chris@16 532 {
Chris@16 533 typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
Chris@16 534 if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
Chris@16 535 {
Chris@16 536 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
Chris@16 537 *result = (std::numeric_limits<R>::max)();
Chris@16 538 }
Chris@16 539 else
Chris@16 540 *result = static_cast<R>(*val.limbs());
Chris@16 541 if(val.isneg())
Chris@16 542 {
Chris@16 543 check_is_negative(mpl::bool_<boost::is_signed<R>::value || boost::is_floating_point<R>::value>());
Chris@16 544 *result = negate_integer(*result, mpl::bool_<boost::is_signed<R>::value || boost::is_floating_point<R>::value>());
Chris@16 545 }
Chris@16 546 }
Chris@16 547
Chris@16 548 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 549 inline typename enable_if_c<
Chris@16 550 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 551 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
Chris@16 552 >::type
Chris@16 553 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
Chris@16 554 {
Chris@16 555 typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
Chris@16 556 if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
Chris@16 557 {
Chris@16 558 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
Chris@16 559 *result = (std::numeric_limits<R>::max)();
Chris@16 560 }
Chris@16 561 else
Chris@16 562 *result = static_cast<R>(*val.limbs());
Chris@16 563 }
Chris@16 564
Chris@16 565 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 566 inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
Chris@16 567 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
Chris@16 568 {
Chris@16 569 using default_ops::eval_get_sign;
Chris@16 570 if(eval_get_sign(a) == 0)
Chris@16 571 {
Chris@16 572 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
Chris@16 573 }
Chris@16 574 if(a.sign())
Chris@16 575 {
Chris@16 576 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
Chris@16 577 }
Chris@16 578 //
Chris@16 579 // Find the index of the least significant bit within that limb:
Chris@16 580 //
Chris@16 581 return boost::multiprecision::detail::find_lsb(*a.limbs());
Chris@16 582 }
Chris@16 583
Chris@16 584 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
Chris@16 585 inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
Chris@16 586 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
Chris@16 587 {
Chris@16 588 using default_ops::eval_get_sign;
Chris@16 589 if(eval_get_sign(a) == 0)
Chris@16 590 {
Chris@16 591 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
Chris@16 592 }
Chris@16 593 if(a.sign())
Chris@16 594 {
Chris@16 595 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
Chris@16 596 }
Chris@16 597 //
Chris@16 598 // Find the index of the least significant bit within that limb:
Chris@16 599 //
Chris@16 600 return boost::multiprecision::detail::find_msb(*a.limbs());
Chris@16 601 }
Chris@16 602
Chris@16 603 #ifdef BOOST_MSVC
Chris@16 604 #pragma warning(pop)
Chris@16 605 #endif
Chris@16 606
Chris@16 607 }}} // namespaces
Chris@16 608
Chris@16 609 #endif