Squashed 'boost/' content from commit b4feb19f2

git-subtree-dir: boost
git-subtree-split: b4feb19f287ee92d87a9624b5d36b7cf46aeadeb
This commit is contained in:
Bill Somerville
2018-06-09 21:48:32 +01:00
commit 4ebe6417a5
12444 changed files with 2327021 additions and 0 deletions
+550
View File
@@ -0,0 +1,550 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_ADD_HPP
#define BOOST_MP_CPP_INT_ADD_HPP
namespace boost{ namespace multiprecision{ namespace backends{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#endif
//
// This is the key addition routine where all the argument types are non-trivial cpp_int's:
//
template <class CppInt1, class CppInt2, class CppInt3>
inline void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
{
using std::swap;
// Nothing fancy, just let uintmax_t take the strain:
double_limb_type carry = 0;
unsigned m, x;
unsigned as = a.size();
unsigned bs = b.size();
minmax(as, bs, m, x);
if(x == 1)
{
bool s = a.sign();
result = static_cast<double_limb_type>(*a.limbs()) + static_cast<double_limb_type>(*b.limbs());
result.sign(s);
return;
}
result.resize(x, x);
typename CppInt2::const_limb_pointer pa = a.limbs();
typename CppInt3::const_limb_pointer pb = b.limbs();
typename CppInt1::limb_pointer pr = result.limbs();
typename CppInt1::limb_pointer pr_end = pr + m;
if(as < bs)
swap(pa, pb);
// First where a and b overlap:
while(pr != pr_end)
{
carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb);
#ifdef __MSVC_RUNTIME_CHECKS
*pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
*pr = static_cast<limb_type>(carry);
#endif
carry >>= CppInt1::limb_bits;
++pr, ++pa, ++pb;
}
pr_end += x - m;
// Now where only a has digits:
while(pr != pr_end)
{
if(!carry)
{
if(pa != pr)
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
std::copy(pa, pa + (pr_end - pr), stdext::checked_array_iterator<limb_type*>(pr, result.size()));
#else
std::copy(pa, pa + (pr_end - pr), pr);
#endif
break;
}
carry += static_cast<double_limb_type>(*pa);
#ifdef __MSVC_RUNTIME_CHECKS
*pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
*pr = static_cast<limb_type>(carry);
#endif
carry >>= CppInt1::limb_bits;
++pr, ++pa;
}
if(carry)
{
// We overflowed, need to add one more limb:
result.resize(x + 1, x + 1);
if(CppInt1::variable || (result.size() > x))
result.limbs()[x] = static_cast<limb_type>(carry);
}
result.normalize();
result.sign(a.sign());
}
//
// As above, but for adding a single limb to a non-trivial cpp_int:
//
template <class CppInt1, class CppInt2>
inline void add_unsigned(CppInt1& result, const CppInt2& a, const limb_type& o) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
{
// Addition using modular arithmetic.
// Nothing fancy, just let uintmax_t take the strain:
if(&result != &a)
result.resize(a.size(), a.size());
double_limb_type carry = o;
typename CppInt1::limb_pointer pr = result.limbs();
typename CppInt2::const_limb_pointer pa = a.limbs();
unsigned i = 0;
// Addition with carry until we either run out of digits or carry is zero:
for(; carry && (i < result.size()); ++i)
{
carry += static_cast<double_limb_type>(pa[i]);
#ifdef __MSVC_RUNTIME_CHECKS
pr[i] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
pr[i] = static_cast<limb_type>(carry);
#endif
carry >>= CppInt1::limb_bits;
}
// Just copy any remaining digits:
if(&a != &result)
{
for(; i < result.size(); ++i)
pr[i] = pa[i];
}
if(carry)
{
// We overflowed, need to add one more limb:
unsigned x = result.size();
result.resize(x + 1, x + 1);
if(CppInt1::variable || (result.size() > x))
result.limbs()[x] = static_cast<limb_type>(carry);
}
result.normalize();
result.sign(a.sign());
}
//
// Core subtraction routine for all non-trivial cpp_int's:
//
template <class CppInt1, class CppInt2, class CppInt3>
inline void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
{
using std::swap;
// Nothing fancy, just let uintmax_t take the strain:
double_limb_type borrow = 0;
unsigned m, x;
minmax(a.size(), b.size(), m, x);
//
// special cases for small limb counts:
//
if(x == 1)
{
bool s = a.sign();
limb_type al = *a.limbs();
limb_type bl = *b.limbs();
if(bl > al)
{
std::swap(al, bl);
s = !s;
}
result = al - bl;
result.sign(s);
return;
}
// This isn't used till later, but comparison has to occur before we resize the result,
// as that may also resize a or b if this is an inplace operation:
int c = a.compare_unsigned(b);
// Set up the result vector:
result.resize(x, x);
// Now that a, b, and result are stable, get pointers to their limbs:
typename CppInt2::const_limb_pointer pa = a.limbs();
typename CppInt3::const_limb_pointer pb = b.limbs();
typename CppInt1::limb_pointer pr = result.limbs();
bool swapped = false;
if(c < 0)
{
swap(pa, pb);
swapped = true;
}
else if(c == 0)
{
result = static_cast<limb_type>(0);
return;
}
unsigned i = 0;
// First where a and b overlap:
while(i < m)
{
borrow = static_cast<double_limb_type>(pa[i]) - static_cast<double_limb_type>(pb[i]) - borrow;
pr[i] = static_cast<limb_type>(borrow);
borrow = (borrow >> CppInt1::limb_bits) & 1u;
++i;
}
// Now where only a has digits, only as long as we've borrowed:
while(borrow && (i < x))
{
borrow = static_cast<double_limb_type>(pa[i]) - borrow;
pr[i] = static_cast<limb_type>(borrow);
borrow = (borrow >> CppInt1::limb_bits) & 1u;
++i;
}
// Any remaining digits are the same as those in pa:
if((x != i) && (pa != pr))
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
std::copy(pa + i, pa + x, stdext::checked_array_iterator<limb_type*>(pr + i, result.size() - i));
#else
std::copy(pa + i, pa + x, pr + i);
#endif
BOOST_ASSERT(0 == borrow);
//
// We may have lost digits, if so update limb usage count:
//
result.normalize();
result.sign(a.sign());
if(swapped)
result.negate();
}
//
// And again to subtract a single limb:
//
template <class CppInt1, class CppInt2>
inline void subtract_unsigned(CppInt1& result, const CppInt2& a, const limb_type& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
{
// Subtract one limb.
// Nothing fancy, just let uintmax_t take the strain:
BOOST_STATIC_CONSTANT(double_limb_type, borrow = static_cast<double_limb_type>(CppInt1::max_limb_value) + 1);
result.resize(a.size(), a.size());
typename CppInt1::limb_pointer pr = result.limbs();
typename CppInt2::const_limb_pointer pa = a.limbs();
if(*pa >= b)
{
*pr = *pa - b;
if(&result != &a)
{
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
std::copy(pa + 1, pa + a.size(), stdext::checked_array_iterator<limb_type*>(pr + 1, result.size() - 1));
#else
std::copy(pa + 1, pa + a.size(), pr + 1);
#endif
result.sign(a.sign());
}
else if((result.size() == 1) && (*pr == 0))
{
result.sign(false); // zero is unsigned.
}
}
else if(result.size() == 1)
{
*pr = b - *pa;
result.sign(!a.sign());
}
else
{
*pr = static_cast<limb_type>((borrow + *pa) - b);
unsigned i = 1;
while(!pa[i])
{
pr[i] = CppInt1::max_limb_value;
++i;
}
pr[i] = pa[i] - 1;
if(&result != &a)
{
++i;
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
std::copy(pa + i, pa + a.size(), stdext::checked_array_iterator<limb_type*>(pr + i, result.size() - i));
#else
std::copy(pa + i, pa + a.size(), pr + i);
#endif
}
result.normalize();
result.sign(a.sign());
}
}
//
// Now the actual functions called by the front end, all of which forward to one of the above:
//
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>
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
eval_add(
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))
{
eval_add(result, result, o);
}
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, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
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_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
eval_add(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(a.sign() != b.sign())
{
subtract_unsigned(result, a, b);
return;
}
add_unsigned(result, a, b);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(result.sign())
{
subtract_unsigned(result, result, o);
}
else
add_unsigned(result, result, o);
}
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>
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
eval_add(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(a.sign())
{
subtract_unsigned(result, a, o);
}
else
add_unsigned(result, a, o);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_add(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(o < 0)
eval_subtract(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
else if(o > 0)
eval_add(result, static_cast<limb_type>(o));
}
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>
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
eval_add(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(o < 0)
eval_subtract(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
else if(o > 0)
eval_add(result, a, static_cast<limb_type>(o));
else if(&result != &a)
result = a;
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(result.sign())
{
add_unsigned(result, result, o);
}
else
subtract_unsigned(result, result, o);
}
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>
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
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(a.sign())
{
add_unsigned(result, a, o);
}
else
{
subtract_unsigned(result, a, o);
}
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(o)
{
if(o < 0)
eval_add(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
else
eval_subtract(result, static_cast<limb_type>(o));
}
}
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>
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
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(o)
{
if(o < 0)
eval_add(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
else
eval_subtract(result, a, static_cast<limb_type>(o));
}
else if(&result != &a)
result = a;
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_increment(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
static const limb_type one = 1;
if(!result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
++result.limbs()[0];
else if(result.sign() && result.limbs()[0])
--result.limbs()[0];
else
eval_add(result, one);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_decrement(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
static const limb_type one = 1;
if(!result.sign() && result.limbs()[0])
--result.limbs()[0];
else if(result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
++result.limbs()[0];
else
eval_subtract(result, one);
}
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>
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
eval_subtract(
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))
{
eval_subtract(result, result, o);
}
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, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
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 && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(a.sign() != b.sign())
{
add_unsigned(result, a, b);
return;
}
subtract_unsigned(result, a, b);
}
//
// Simple addition and subtraction routine for trivial cpp_int's come last:
//
// One of the arguments is signed:
//
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
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
>::type
eval_add(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(result.sign() != o.sign())
{
if(*o.limbs() > *result.limbs())
{
*result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.negate();
}
else
*result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
}
else
*result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
// Simple version for two unsigned arguments:
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
// signed subtraction:
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
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
>::type
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(result.sign() != o.sign())
{
*result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
}
else if(*result.limbs() < *o.limbs())
{
*result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.negate();
}
else
*result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_subtract(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}}} // namespaces
#endif
+842
View File
@@ -0,0 +1,842 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_BIT_HPP
#define BOOST_MP_CPP_INT_BIT_HPP
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4319)
#endif
namespace boost{ namespace multiprecision{ namespace backends{
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>
void is_valid_bitwise_op(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::int_<checked>&)
{
if(result.sign() || o.sign())
BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
}
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>
void is_valid_bitwise_op(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& , const mpl::int_<unchecked>&){}
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
void is_valid_bitwise_op(
const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const mpl::int_<checked>&)
{
if(result.sign())
BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
void is_valid_bitwise_op(
const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const mpl::int_<checked>&){}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
void is_valid_bitwise_op(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const mpl::int_<unchecked>&){}
template <class CppInt1, class CppInt2, class Op>
void bitwise_op(
CppInt1& result,
const CppInt2& o,
Op op, const mpl::true_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
{
//
// There are 4 cases:
// * Both positive.
// * result negative, o positive.
// * o negative, result positive.
// * Both negative.
//
// When one arg is negative we convert to 2's complement form "on the fly",
// and then convert back to signed-magnitude form at the end.
//
// Note however, that if the type is checked, then bitwise ops on negative values
// are not permitted and an exception will result.
//
is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
//
// First figure out how big the result needs to be and set up some data:
//
unsigned rs = result.size();
unsigned os = o.size();
unsigned m, x;
minmax(rs, os, m, x);
result.resize(x, x);
typename CppInt1::limb_pointer pr = result.limbs();
typename CppInt2::const_limb_pointer po = o.limbs();
for(unsigned i = rs; i < x; ++i)
pr[i] = 0;
limb_type next_limb = 0;
if(!result.sign())
{
if(!o.sign())
{
for(unsigned i = 0; i < os; ++i)
pr[i] = op(pr[i], po[i]);
for(unsigned i = os; i < x; ++i)
pr[i] = op(pr[i], limb_type(0));
}
else
{
// "o" is negative:
double_limb_type carry = 1;
for(unsigned i = 0; i < os; ++i)
{
carry += static_cast<double_limb_type>(~po[i]);
pr[i] = op(pr[i], static_cast<limb_type>(carry));
carry >>= CppInt1::limb_bits;
}
for(unsigned i = os; i < x; ++i)
{
carry += static_cast<double_limb_type>(~limb_type(0));
pr[i] = op(pr[i], static_cast<limb_type>(carry));
carry >>= CppInt1::limb_bits;
}
// Set the overflow into the "extra" limb:
carry += static_cast<double_limb_type>(~limb_type(0));
next_limb = op(limb_type(0), static_cast<limb_type>(carry));
}
}
else
{
if(!o.sign())
{
// "result" is negative:
double_limb_type carry = 1;
for(unsigned i = 0; i < os; ++i)
{
carry += static_cast<double_limb_type>(~pr[i]);
pr[i] = op(static_cast<limb_type>(carry), po[i]);
carry >>= CppInt1::limb_bits;
}
for(unsigned i = os; i < x; ++i)
{
carry += static_cast<double_limb_type>(~pr[i]);
pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
carry >>= CppInt1::limb_bits;
}
// Set the overflow into the "extra" limb:
carry += static_cast<double_limb_type>(~limb_type(0));
next_limb = op(static_cast<limb_type>(carry), limb_type(0));
}
else
{
// both are negative:
double_limb_type r_carry = 1;
double_limb_type o_carry = 1;
for(unsigned i = 0; i < os; ++i)
{
r_carry += static_cast<double_limb_type>(~pr[i]);
o_carry += static_cast<double_limb_type>(~po[i]);
pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
r_carry >>= CppInt1::limb_bits;
o_carry >>= CppInt1::limb_bits;
}
for(unsigned i = os; i < x; ++i)
{
r_carry += static_cast<double_limb_type>(~pr[i]);
o_carry += static_cast<double_limb_type>(~limb_type(0));
pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
r_carry >>= CppInt1::limb_bits;
o_carry >>= CppInt1::limb_bits;
}
// Set the overflow into the "extra" limb:
r_carry += static_cast<double_limb_type>(~limb_type(0));
o_carry += static_cast<double_limb_type>(~limb_type(0));
next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
}
}
//
// See if the result is negative or not:
//
if(static_cast<signed_limb_type>(next_limb) < 0)
{
double_limb_type carry = 1;
for(unsigned i = 0; i < x; ++i)
{
carry += static_cast<double_limb_type>(~pr[i]);
pr[i] = static_cast<limb_type>(carry);
carry >>= CppInt1::limb_bits;
}
if(carry)
{
result.resize(x + 1, x);
if(result.size() > x)
result.limbs()[x] = static_cast<limb_type>(carry);
}
result.sign(true);
}
else
result.sign(false);
result.normalize();
}
template <class CppInt1, class CppInt2, class Op>
void bitwise_op(
CppInt1& result,
const CppInt2& o,
Op op, const mpl::false_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
{
//
// Both arguments are unsigned types, very simple case handled as a special case.
//
// First figure out how big the result needs to be and set up some data:
//
unsigned rs = result.size();
unsigned os = o.size();
unsigned m, x;
minmax(rs, os, m, x);
result.resize(x, x);
typename CppInt1::limb_pointer pr = result.limbs();
typename CppInt2::const_limb_pointer po = o.limbs();
for(unsigned i = rs; i < x; ++i)
pr[i] = 0;
for(unsigned i = 0; i < os; ++i)
pr[i] = op(pr[i], po[i]);
for(unsigned i = os; i < x; ++i)
pr[i] = op(pr[i], limb_type(0));
result.normalize();
}
struct bit_and{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a & b; } };
struct bit_or { limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a | b; } };
struct bit_xor{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a ^ b; } };
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>
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
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))
{
bitwise_op(result, o, bit_and(),
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>());
}
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>
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
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))
{
bitwise_op(result, o, bit_or(),
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>());
}
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>
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
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))
{
bitwise_op(result, o, bit_xor(),
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>());
}
//
// Again for operands which are single limbs:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
eval_bitwise_and(
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
limb_type l) BOOST_NOEXCEPT
{
result.limbs()[0] &= l;
result.resize(1, 1);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
eval_bitwise_or(
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
limb_type l) BOOST_NOEXCEPT
{
result.limbs()[0] |= l;
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
eval_bitwise_xor(
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
limb_type l) BOOST_NOEXCEPT
{
result.limbs()[0] ^= l;
}
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>
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
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))
{
BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
// Increment and negate:
result = o;
eval_increment(result);
result.negate();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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
eval_complement(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
unsigned os = o.size();
result.resize(UINT_MAX, os);
for(unsigned i = 0; i < os; ++i)
result.limbs()[i] = ~o.limbs()[i];
for(unsigned i = os; i < result.size(); ++i)
result.limbs()[i] = ~static_cast<limb_type>(0);
result.normalize();
}
template <class Int>
inline void left_shift_byte(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);
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);
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;
}
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] >> (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;
}
unsigned i = rs - result.size();
// This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
BOOST_ASSERT(shift);
if(!truncated)
{
if(rs > ors + offset)
{
pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::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] >> (Int::limb_bits - shift);
++i;
}
}
for(; ors > 1 + i; ++i)
{
pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
}
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_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))
{
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, 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, 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();
}
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)
{
result = limb_type(0);
return;
}
rs -= offset;
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)
{
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;
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)
{
if(--rs == 0)
{
result = limb_type(0);
return;
}
}
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)
{
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);
}
//
// Over again for trivial cpp_int's:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
*result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
// 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.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>
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_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(
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())
{
*result.limbs() = *o.limbs() - 1;
result.sign(false);
}
else
{
*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>
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_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))
{
*result.limbs() &= *o.limbs();
}
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_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(
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())
{
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);
}
else
{
*result.limbs() &= *o.limbs();
}
}
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_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))
{
*result.limbs() |= *o.limbs();
}
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_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(
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())
{
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);
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() |= *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_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))
{
*result.limbs() ^= *o.limbs();
}
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_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(
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())
{
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() ^= *o.limbs();
}
}
}}} // namespaces
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif
+149
View File
@@ -0,0 +1,149 @@
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
#ifndef BOOST_MP_CPP_INT_CHECKED_HPP
#define BOOST_MP_CPP_INT_CHECKED_HPP
namespace boost{ namespace multiprecision{ namespace backends{ namespace detail{
//
// Simple routines for performing checked arithmetic with a builtin arithmetic type.
// Note that this is not a complete header, it must be included as part of boost/multiprecision/cpp_int.hpp.
//
inline void raise_overflow(std::string op)
{
BOOST_THROW_EXCEPTION(std::overflow_error("overflow in " + op));
}
inline void raise_add_overflow()
{
raise_overflow("addition");
}
inline void raise_subtract_overflow()
{
BOOST_THROW_EXCEPTION(std::range_error("Subtraction resulted in a negative value, but the type is unsigned"));
}
inline void raise_mul_overflow()
{
raise_overflow("multiplication");
}
inline void raise_div_overflow()
{
raise_overflow("division");
}
template <class A>
inline A checked_add_imp(A a, A b, const mpl::true_&)
{
if(a > 0)
{
if((b > 0) && ((integer_traits<A>::const_max - b) < a))
raise_add_overflow();
}
else
{
if((b < 0) && ((integer_traits<A>::const_min - b) > a))
raise_add_overflow();
}
return a + b;
}
template <class A>
inline A checked_add_imp(A a, A b, const mpl::false_&)
{
if((integer_traits<A>::const_max - b) < a)
raise_add_overflow();
return a + b;
}
template <class A>
inline A checked_add(A a, A b, const mpl::int_<checked>&)
{
return checked_add_imp(a, b, boost::is_signed<A>());
}
template <class A>
inline A checked_add(A a, A b, const mpl::int_<unchecked>&)
{
return a + b;
}
template <class A>
inline A checked_subtract_imp(A a, A b, const mpl::true_&)
{
if(a > 0)
{
if((b < 0) && ((integer_traits<A>::const_max + b) < a))
raise_subtract_overflow();
}
else
{
if((b > 0) && ((integer_traits<A>::const_min + b) > a))
raise_subtract_overflow();
}
return a - b;
}
template <class A>
inline A checked_subtract_imp(A a, A b, const mpl::false_&)
{
if(a < b)
raise_subtract_overflow();
return a - b;
}
template <class A>
inline A checked_subtract(A a, A b, const mpl::int_<checked>&)
{
return checked_subtract_imp(a, b, boost::is_signed<A>());
}
template <class A>
inline A checked_subtract(A a, A b, const mpl::int_<unchecked>&)
{
return a - b;
}
template <class A>
inline A checked_multiply(A a, A b, const mpl::int_<checked>&)
{
BOOST_MP_USING_ABS
if(a && (integer_traits<A>::const_max / abs(a) < abs(b)))
raise_mul_overflow();
return a * b;
}
template <class A>
inline A checked_multiply(A a, A b, const mpl::int_<unchecked>&)
{
return a * b;
}
template <class A>
inline A checked_divide(A a, A b, const mpl::int_<checked>&)
{
if(b == 0)
raise_div_overflow();
return a / b;
}
template <class A>
inline A checked_divide(A a, A b, const mpl::int_<unchecked>&)
{
return a / b;
}
template <class A>
inline A checked_left_shift(A a, boost::ulong_long_type shift, const mpl::int_<checked>&)
{
if(a && shift)
{
if((shift > sizeof(A) * CHAR_BIT) || (a >> (sizeof(A) * CHAR_BIT - shift)))
BOOST_THROW_EXCEPTION(std::overflow_error("Shift out of range"));
}
return a << shift;
}
template <class A>
inline A checked_left_shift(A a, boost::ulong_long_type shift, const mpl::int_<unchecked>&)
{
return (shift >= sizeof(A) * CHAR_BIT) ? 0 : a << shift;
}
}}}} // namespaces
#endif
+399
View File
@@ -0,0 +1,399 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_COMPARISON_HPP
#define BOOST_MP_CPP_INT_COMPARISON_HPP
#include <boost/type_traits/make_unsigned.hpp>
namespace boost{ namespace multiprecision{ namespace backends{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4018 4389 4996)
#endif
//
// Start with non-trivial cpp_int's:
//
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value,
bool
>::type
eval_eq(const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& a, const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& b) BOOST_NOEXCEPT
{
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
return (a.sign() == b.sign())
&& (a.size() == b.size())
&& std::equal(a.limbs(), a.limbs() + a.size(),
stdext::checked_array_iterator<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::const_limb_pointer>(b.limbs(), b.size()));
#else
return (a.sign() == b.sign())
&& (a.size() == b.size())
&& std::equal(a.limbs(), a.limbs() + a.size(), b.limbs());
#endif
}
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>
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,
bool
>::type
eval_eq(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b) BOOST_NOEXCEPT
{
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
return (a.sign() == b.sign())
&& (a.size() == b.size())
&& std::equal(a.limbs(), a.limbs() + a.size(), stdext::checked_array_iterator<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer>(b.limbs(), b.size()));
#else
return (a.sign() == b.sign())
&& (a.size() == b.size())
&& std::equal(a.limbs(), a.limbs() + a.size(), b.limbs());
#endif
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
{
return (a.sign() == false)
&& (a.size() == 1)
&& (*a.limbs() == b);
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
{
return (a.sign() == (b < 0))
&& (a.size() == 1)
&& (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b));
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
{
return (a.size() == 1)
&& (*a.limbs() == b);
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
{
return (b < 0) ? eval_eq(a, cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>(b)) : eval_eq(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
{
if(a.sign())
return true;
if(a.size() > 1)
return false;
return *a.limbs() < b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
inline typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
{
if((b == 0) || (a.sign() != (b < 0)))
return a.sign();
if(a.sign())
{
if(a.size() > 1)
return true;
return *a.limbs() > boost::multiprecision::detail::unsigned_abs(b);
}
else
{
if(a.size() > 1)
return false;
return *a.limbs() < boost::multiprecision::detail::unsigned_abs(b);
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
{
if(a.size() > 1)
return false;
return *a.limbs() < b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
{
return (b < 0) ? a.compare(b) < 0 : eval_lt(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
{
if(a.sign())
return false;
if(a.size() > 1)
return true;
return *a.limbs() > b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
inline typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
{
if(b == 0)
return !a.sign() && ((a.size() > 1) || *a.limbs());
if(a.sign() != (b < 0))
return !a.sign();
if(a.sign())
{
if(a.size() > 1)
return false;
return *a.limbs() < boost::multiprecision::detail::unsigned_abs(b);
}
else
{
if(a.size() > 1)
return true;
return *a.limbs() > boost::multiprecision::detail::unsigned_abs(b);
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
{
if(a.size() > 1)
return true;
return *a.limbs() > b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
{
return (b < 0) ? a.compare(b) > 0 : eval_gt(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison.
}
//
// And again for trivial cpp_ints:
//
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::value eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& b) BOOST_NOEXCEPT
{
return (a.sign() == b.sign()) && (*a.limbs() == *b.limbs());
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::value eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
{
return *a.limbs() == *b.limbs();
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
{
return !a.sign() && (*a.limbs() == b);
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
{
return (a.sign() == (b < 0)) && (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b));
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
{
return *a.limbs() == b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
{
typedef typename make_unsigned<S>::type ui_type;
if(b < 0)
{
cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> t(b);
return *a.limbs() == *t.limbs();
}
else
{
return *a.limbs() == static_cast<ui_type>(b);
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
{
if(a.sign() != b.sign())
return a.sign();
return a.sign() ? *a.limbs() > *b.limbs() : *a.limbs() < *b.limbs();
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
{
return *a.limbs() < *b.limbs();
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
{
if(a.sign())
return true;
return *a.limbs() < b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
{
if(a.sign() != (b < 0))
return a.sign();
return a.sign() ? (*a.limbs() > boost::multiprecision::detail::unsigned_abs(b)) : (*a.limbs() < boost::multiprecision::detail::unsigned_abs(b));
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
{
return *a.limbs() < b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
{
typedef typename make_unsigned<S>::type ui_type;
if(b < 0)
{
cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> t(b);
return *a.limbs() < *t.limbs();
}
else
{
return *a.limbs() < static_cast<ui_type>(b);
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& b) BOOST_NOEXCEPT
{
if(a.sign() != b.sign())
return !a.sign();
return a.sign() ? *a.limbs() < *b.limbs() : *a.limbs() > *b.limbs();
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
{
return *a.limbs() > *b.limbs();
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
{
if(a.sign())
return false;
return *a.limbs() > b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
{
if(a.sign() != (b < 0))
return !a.sign();
return a.sign() ? (*a.limbs() < boost::multiprecision::detail::unsigned_abs(b)) : (*a.limbs() > boost::multiprecision::detail::unsigned_abs(b));
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
{
return *a.limbs() > b;
}
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
bool
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
{
typedef typename make_unsigned<S>::type ui_type;
if(b < 0)
{
cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> t(b);
return *a.limbs() > *t.limbs();
}
else
{
return *a.limbs() > static_cast<ui_type>(b);
}
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}}} // namespaces
#endif
@@ -0,0 +1,163 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
#ifndef BOOST_MP_CPP_INT_CORE_HPP
#define BOOST_MP_CPP_INT_CORE_HPP
#include <boost/integer.hpp>
#include <boost/integer_traits.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/static_assert.hpp>
#include <boost/assert.hpp>
namespace boost{ namespace multiprecision{
namespace detail{
//
// These traits calculate the largest type in the list
// [unsigned] boost::long_long_type, long, int, which has the specified number
// of bits. Note that intN_t and boost::int_t<N> find the first
// member of the above list, not the last. We want the last in the
// list to ensure that mixed arithmetic operations are as efficient
// as possible.
//
template <unsigned N>
struct largest_signed_type
{
typedef typename mpl::if_c<
1 + std::numeric_limits<boost::long_long_type>::digits == N,
boost::long_long_type,
typename mpl::if_c<
1 + std::numeric_limits<long>::digits == N,
long,
typename mpl::if_c<
1 + std::numeric_limits<int>::digits == N,
int,
typename boost::int_t<N>::exact
>::type
>::type
>::type type;
};
template <unsigned N>
struct largest_unsigned_type
{
typedef typename mpl::if_c<
std::numeric_limits<boost::ulong_long_type>::digits == N,
boost::ulong_long_type,
typename mpl::if_c<
std::numeric_limits<unsigned long>::digits == N,
unsigned long,
typename mpl::if_c<
std::numeric_limits<unsigned int>::digits == N,
unsigned int,
typename boost::uint_t<N>::exact
>::type
>::type
>::type type;
};
} // namespace detail
#if defined(BOOST_HAS_INT128)
typedef detail::largest_unsigned_type<64>::type limb_type;
typedef detail::largest_signed_type<64>::type signed_limb_type;
typedef boost::uint128_type double_limb_type;
typedef boost::int128_type signed_double_limb_type;
static const limb_type max_block_10 = 1000000000000000000uLL;
static const limb_type digits_per_block_10 = 18;
inline limb_type block_multiplier(unsigned count)
{
static const limb_type values[digits_per_block_10]
= { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000 };
BOOST_ASSERT(count < digits_per_block_10);
return values[count];
}
// Can't do formatted IO on an __int128
#define BOOST_MP_NO_DOUBLE_LIMB_TYPE_IO
// Need to specialise integer_traits for __int128 as it's not a normal native type:
} // namespace multiprecision
template<>
class integer_traits<multiprecision::double_limb_type>
: public std::numeric_limits<multiprecision::double_limb_type>,
public detail::integer_traits_base<multiprecision::double_limb_type, 0, ~static_cast<multiprecision::double_limb_type>(0)>
{ };
template<>
class integer_traits<multiprecision::signed_double_limb_type>
: public std::numeric_limits<multiprecision::signed_double_limb_type>,
public detail::integer_traits_base<multiprecision::signed_double_limb_type, static_cast<multiprecision::signed_double_limb_type>((static_cast<multiprecision::double_limb_type>(1) << 127)), static_cast<multiprecision::signed_double_limb_type>(((~static_cast<multiprecision::double_limb_type>(0)) >> 1))>
{ };
namespace multiprecision{
#else
typedef detail::largest_unsigned_type<32>::type limb_type;
typedef detail::largest_signed_type<32>::type signed_limb_type;
typedef detail::largest_unsigned_type<64>::type double_limb_type;
typedef detail::largest_signed_type<64>::type signed_double_limb_type;
static const limb_type max_block_10 = 1000000000;
static const limb_type digits_per_block_10 = 9;
inline limb_type block_multiplier(unsigned count)
{
static const limb_type values[digits_per_block_10]
= { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
BOOST_ASSERT(count < digits_per_block_10);
return values[count];
}
#endif
static const unsigned bits_per_limb = sizeof(limb_type) * CHAR_BIT;
template <class T>
inline void minmax(const T& a, const T& b, T& aa, T& bb)
{
if(a < b)
{
aa = a;
bb = b;
}
else
{
aa = b;
bb = a;
}
}
enum cpp_integer_type
{
signed_magnitude = 1,
unsigned_magnitude = 0,
signed_packed = 3,
unsigned_packed = 2
};
enum cpp_int_check_type
{
checked = 1,
unchecked = 0
};
}}
//
// Figure out whether to support user-defined-literals or not:
//
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_USER_DEFINED_LITERALS) \
&& !defined(BOOST_NO_CXX11_CONSTEXPR)
# define BOOST_MP_USER_DEFINED_LITERALS
#endif
#endif // BOOST_MP_CPP_INT_CORE_HPP
+655
View File
@@ -0,0 +1,655 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_DIV_HPP
#define BOOST_MP_CPP_INT_DIV_HPP
namespace boost{ namespace multiprecision{ namespace backends{
template <class CppInt1, class CppInt2, class CppInt3>
void divide_unsigned_helper(
CppInt1* result,
const CppInt2& x,
const CppInt3& y,
CppInt1& r)
{
if(((void*)result == (void*)&x) || ((void*)&r == (void*)&x))
{
CppInt2 t(x);
divide_unsigned_helper(result, t, y, r);
return;
}
if(((void*)result == (void*)&y) || ((void*)&r == (void*)&y))
{
CppInt3 t(y);
divide_unsigned_helper(result, x, t, r);
return;
}
/*
Very simple, fairly braindead long division.
Start by setting the remainder equal to x, and the
result equal to 0. Then in each loop we calculate our
"best guess" for how many times y divides into r,
add our guess to the result, and subtract guess*y
from the remainder r. One wrinkle is that the remainder
may go negative, in which case we subtract the current guess
from the result rather than adding. The value of the guess
is determined by dividing the most-significant-limb of the
current remainder by the most-significant-limb of y.
Note that there are more efficient algorithms than this
available, in particular see Knuth Vol 2. However for small
numbers of limbs this generally outperforms the alternatives
and avoids the normalisation step which would require extra storage.
*/
using default_ops::eval_subtract;
if(result == &r)
{
CppInt1 rem;
divide_unsigned_helper(result, x, y, rem);
r = rem;
return;
}
//
// Find the most significant words of numerator and denominator.
//
limb_type y_order = y.size() - 1;
if(y_order == 0)
{
//
// Only a single non-zero limb in the denominator, in this case
// we can use a specialized divide-by-single-limb routine which is
// much faster. This also handles division by zero:
//
divide_unsigned_helper(result, x, y.limbs()[y_order], r);
return;
}
typename CppInt2::const_limb_pointer px = x.limbs();
typename CppInt3::const_limb_pointer py = y.limbs();
limb_type r_order = x.size() - 1;
if((r_order == 0) && (*px == 0))
{
// x is zero, so is the result:
r = x;
if(result)
*result = x;
return;
}
r = x;
r.sign(false);
if(result)
*result = static_cast<limb_type>(0u);
//
// Check if the remainder is already less than the divisor, if so
// we already have the result. Note we try and avoid a full compare
// if we can:
//
if(r_order <= y_order)
{
if((r_order < y_order) || (r.compare_unsigned(y) < 0))
{
return;
}
}
CppInt1 t;
bool r_neg = false;
//
// See if we can short-circuit long division, and use basic arithmetic instead:
//
if(r_order == 0)
{
if(result)
{
*result = px[0] / py[0];
}
r = px[0] % py[0];
return;
}
else if(r_order == 1)
{
double_limb_type a, b;
a = (static_cast<double_limb_type>(px[1]) << CppInt1::limb_bits) | px[0];
b = y_order ?
(static_cast<double_limb_type>(py[1]) << CppInt1::limb_bits) | py[0]
: py[0];
if(result)
{
*result = a / b;
}
r = a % b;
return;
}
//
// prepare result:
//
if(result)
result->resize(1 + r_order - y_order, 1 + r_order - y_order);
typename CppInt1::const_limb_pointer prem = r.limbs();
// This is initialised just to keep the compiler from emitting useless warnings later on:
typename CppInt1::limb_pointer pr
= typename CppInt1::limb_pointer();
if(result)
{
pr = result->limbs();
for(unsigned i = 1; i < 1 + r_order - y_order; ++i)
pr[i] = 0;
}
bool first_pass = true;
do
{
//
// Calculate our best guess for how many times y divides into r:
//
limb_type guess;
if((prem[r_order] <= py[y_order]) && (r_order > 0))
{
double_limb_type a, b, v;
a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
b = py[y_order];
v = a / b;
if(v > CppInt1::max_limb_value)
guess = 1;
else
{
guess = static_cast<limb_type>(v);
--r_order;
}
}
else if(r_order == 0)
{
guess = prem[0] / py[y_order];
}
else
{
double_limb_type a, b, v;
a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
b = (y_order > 0) ? (static_cast<double_limb_type>(py[y_order]) << CppInt1::limb_bits) | py[y_order - 1] : (static_cast<double_limb_type>(py[y_order]) << CppInt1::limb_bits);
v = a / b;
guess = static_cast<limb_type>(v);
}
BOOST_ASSERT(guess); // If the guess ever gets to zero we go on forever....
//
// Update result:
//
limb_type shift = r_order - y_order;
if(result)
{
if(r_neg)
{
if(pr[shift] > guess)
pr[shift] -= guess;
else
{
t.resize(shift + 1, shift + 1);
t.limbs()[shift] = guess;
for(unsigned i = 0; i < shift; ++i)
t.limbs()[i] = 0;
eval_subtract(*result, t);
}
}
else if(CppInt1::max_limb_value - pr[shift] > guess)
pr[shift] += guess;
else
{
t.resize(shift + 1, shift + 1);
t.limbs()[shift] = guess;
for(unsigned i = 0; i < shift; ++i)
t.limbs()[i] = 0;
eval_add(*result, t);
}
}
//
// Calculate guess * y, we use a fused mutiply-shift O(N) for this
// rather than a full O(N^2) multiply:
//
double_limb_type carry = 0;
t.resize(y.size() + shift + 1, y.size() + shift);
bool truncated_t = !CppInt1::variable && (t.size() != y.size() + shift + 1);
typename CppInt1::limb_pointer pt = t.limbs();
for(unsigned i = 0; i < shift; ++i)
pt[i] = 0;
for(unsigned i = 0; i < y.size(); ++i)
{
carry += static_cast<double_limb_type>(py[i]) * static_cast<double_limb_type>(guess);
#ifdef __MSVC_RUNTIME_CHECKS
pt[i + shift] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
pt[i + shift] = static_cast<limb_type>(carry);
#endif
carry >>= CppInt1::limb_bits;
}
if(carry && !truncated_t)
{
#ifdef __MSVC_RUNTIME_CHECKS
pt[t.size() - 1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
pt[t.size() - 1] = static_cast<limb_type>(carry);
#endif
}
else if(!truncated_t)
{
t.resize(t.size() - 1, t.size() - 1);
}
//
// Update r in a way that won't actually produce a negative result
// in case the argument types are unsigned:
//
if(truncated_t && carry)
{
// We need to calculate 2^n + t - r
// where n is the number of bits in this type.
// Simplest way is to get 2^n - r by complementing
// r, then add t to it. Note that we can't call eval_complement
// in case this is a signed checked type:
for(unsigned i = 0; i <= r_order; ++i)
r.limbs()[i] = ~prem[i];
r.normalize();
eval_increment(r);
eval_add(r, t);
r_neg = !r_neg;
}
else if(r.compare(t) > 0)
{
eval_subtract(r, t);
}
else
{
r.swap(t);
eval_subtract(r, t);
prem = r.limbs();
r_neg = !r_neg;
}
//
// First time through we need to strip any leading zero, otherwise
// the termination condition goes belly-up:
//
if(result && first_pass)
{
first_pass = false;
while(pr[result->size() - 1] == 0)
result->resize(result->size() - 1, result->size() - 1);
}
//
// Update r_order:
//
r_order = r.size() - 1;
if(r_order < y_order)
break;
}
// Termination condition is really just a check that r > y, but with a common
// short-circuit case handled first:
while((r_order > y_order) || (r.compare_unsigned(y) >= 0));
//
// We now just have to normalise the result:
//
if(r_neg && eval_get_sign(r))
{
// We have one too many in the result:
if(result)
eval_decrement(*result);
if(y.sign())
{
r.negate();
eval_subtract(r, y);
}
else
eval_subtract(r, y, r);
}
BOOST_ASSERT(r.compare_unsigned(y) < 0); // remainder must be less than the divisor or our code has failed
}
template <class CppInt1, class CppInt2>
void divide_unsigned_helper(
CppInt1* result,
const CppInt2& x,
limb_type y,
CppInt1& r)
{
if(((void*)result == (void*)&x) || ((void*)&r == (void*)&x))
{
CppInt2 t(x);
divide_unsigned_helper(result, t, y, r);
return;
}
if(result == &r)
{
CppInt1 rem;
divide_unsigned_helper(result, x, y, rem);
r = rem;
return;
}
// As above, but simplified for integer divisor:
using default_ops::eval_subtract;
if(y == 0)
{
BOOST_THROW_EXCEPTION(std::overflow_error("Integer Division by zero."));
}
//
// Find the most significant word of numerator.
//
limb_type r_order = x.size() - 1;
//
// Set remainder and result to their initial values:
//
r = x;
r.sign(false);
typename CppInt1::limb_pointer pr = r.limbs();
//
// check for x < y, try to do this without actually having to
// do a full comparison:
//
if((r_order == 0) && (*pr < y))
{
if(result)
*result = static_cast<limb_type>(0u);
return;
}
//
// See if we can short-circuit long division, and use basic arithmetic instead:
//
if(r_order == 0)
{
if(result)
{
*result = *pr / y;
result->sign(x.sign());
}
*pr %= y;
r.sign(x.sign());
return;
}
else if(r_order == 1)
{
double_limb_type a;
a = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[0];
if(result)
{
*result = a / y;
result->sign(x.sign());
}
r = a % y;
r.sign(x.sign());
return;
}
// This is initialised just to keep the compiler from emitting useless warnings later on:
typename CppInt1::limb_pointer pres = typename CppInt1::limb_pointer();
if(result)
{
result->resize(r_order + 1, r_order + 1);
pres = result->limbs();
if(result->size() > r_order)
pres[r_order] = 0; // just in case we don't set the most significant limb below.
}
do
{
//
// Calculate our best guess for how many times y divides into r:
//
if((pr[r_order] < y) && r_order)
{
double_limb_type a, b;
a = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[r_order - 1];
b = a % y;
r.resize(r.size() - 1, r.size() - 1);
--r_order;
pr[r_order] = static_cast<limb_type>(b);
if(result)
pres[r_order] = static_cast<limb_type>(a / y);
if(r_order && pr[r_order] == 0)
{
--r_order; // No remainder, division was exact.
r.resize(r.size() - 1, r.size() - 1);
if(result)
pres[r_order] = static_cast<limb_type>(0u);
}
}
else
{
if(result)
pres[r_order] = pr[r_order] / y;
pr[r_order] %= y;
if(r_order && pr[r_order] == 0)
{
--r_order; // No remainder, division was exact.
r.resize(r.size() - 1, r.size() - 1);
if(result)
pres[r_order] = static_cast<limb_type>(0u);
}
}
}
// Termination condition is really just a check that r >= y, but with two common
// short-circuit cases handled first:
while(r_order || (pr[r_order] >= y));
if(result)
{
result->normalize();
result->sign(x.sign());
}
r.normalize();
r.sign(x.sign());
BOOST_ASSERT(r.compare(y) < 0); // remainder must be less than the divisor or our code has failed
}
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, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
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 && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
{
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
bool s = a.sign() != b.sign();
divide_unsigned_helper(&result, a, b, r);
result.sign(s);
}
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>
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
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
limb_type& b)
{
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
bool s = a.sign();
divide_unsigned_helper(&result, a, b, r);
result.sign(s);
}
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>
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
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
signed_limb_type& b)
{
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
bool s = a.sign() != (b < 0);
divide_unsigned_helper(&result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(b)), r);
result.sign(s);
}
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>
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
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b)
{
// There is no in place divide:
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
eval_divide(result, a, b);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
limb_type b)
{
// There is no in place divide:
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
eval_divide(result, a, b);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
signed_limb_type b)
{
// There is no in place divide:
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
eval_divide(result, a, b);
}
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, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
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 && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
{
bool s = a.sign();
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>* >(0), a, b, result);
result.sign(s);
}
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>
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
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a, limb_type b)
{
bool s = a.sign();
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>* >(0), a, b, result);
result.sign(s);
}
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>
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
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
signed_limb_type b)
{
bool s = a.sign();
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>* >(0), a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(b)), result);
result.sign(s);
}
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>
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
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b)
{
// There is no in place divide:
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
eval_modulus(result, a, b);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
limb_type b)
{
// There is no in place divide:
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
eval_modulus(result, a, b);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
signed_limb_type b)
{
// There is no in place divide:
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
eval_modulus(result, a, b);
}
//
// Over again for trivial cpp_int's:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
>::type
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
{
if(!*o.limbs())
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
*result.limbs() /= *o.limbs();
result.sign(result.sign() != o.sign());
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_divide(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
{
if(!*o.limbs())
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
*result.limbs() /= *o.limbs();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_modulus(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
{
if(!*o.limbs())
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
*result.limbs() %= *o.limbs();
result.sign(result.sign());
}
}}} // namespaces
#endif
@@ -0,0 +1,252 @@
///////////////////////////////////////////////////////////////
// Copyright 2015 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
#ifndef BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
#define BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
namespace boost {
namespace multiprecision {
namespace detail {
template <class Backend, class Unsigned>
void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::false_& tag)
{
unsigned limb = bit_location / (sizeof(limb_type) * CHAR_BIT);
unsigned shift = bit_location % (sizeof(limb_type) * CHAR_BIT);
limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT ? ~static_cast<limb_type>(0u) : (static_cast<limb_type>(1u) << chunk_bits) - 1;
limb_type value = static_cast<limb_type>(bits & mask) << shift;
if(value)
{
if(val.size() == limb)
{
val.resize(limb + 1, limb + 1);
if(val.size() > limb)
val.limbs()[limb] = value;
}
else if(val.size() > limb)
val.limbs()[limb] |= value;
}
if(chunk_bits > sizeof(limb_type) * CHAR_BIT - shift)
{
shift = sizeof(limb_type) * CHAR_BIT - shift;
chunk_bits -= shift;
bit_location += shift;
bits >>= shift;
if(bits)
assign_bits(val, bits, bit_location, chunk_bits, tag);
}
}
template <class Backend, class Unsigned>
void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::true_&)
{
typedef typename Backend::local_limb_type local_limb_type;
//
// Check for possible overflow, this may trigger an exception, or have no effect
// depending on whether this is a checked integer or not:
//
if((bit_location >= sizeof(local_limb_type) * CHAR_BIT) && bits)
val.resize(2, 2);
else
{
local_limb_type mask = chunk_bits >= sizeof(local_limb_type) * CHAR_BIT ? ~static_cast<local_limb_type>(0u) : (static_cast<local_limb_type>(1u) << chunk_bits) - 1;
local_limb_type value = (static_cast<local_limb_type>(bits) & mask) << bit_location;
*val.limbs() |= value;
//
// Check for overflow bits:
//
bit_location = sizeof(local_limb_type) * CHAR_BIT - bit_location;
bits >>= bit_location;
if(bits)
val.resize(2, 2); // May throw!
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned bits, const mpl::false_&)
{
unsigned limb_count = static_cast<unsigned>(bits / (sizeof(limb_type) * CHAR_BIT));
if(bits % (sizeof(limb_type) * CHAR_BIT))
++limb_count;
static const unsigned max_limbs = MaxBits ? MaxBits / (CHAR_BIT * sizeof(limb_type)) + ((MaxBits % (CHAR_BIT * sizeof(limb_type))) ? 1 : 0) : (std::numeric_limits<unsigned>::max)();
if(limb_count > max_limbs)
limb_count = max_limbs;
newval.resize(limb_count, limb_count);
std::memset(newval.limbs(), 0, newval.size() * sizeof(limb_type));
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned, const mpl::true_&)
{
*newval.limbs() = 0;
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
import_bits_generic(
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
{
typename number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>::backend_type newval;
typedef typename std::iterator_traits<Iterator>::value_type value_type;
typedef typename boost::make_unsigned<value_type>::type unsigned_value_type;
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
if(!chunk_size)
chunk_size = std::numeric_limits<value_type>::digits;
size_type limbs = std::distance(i, j);
size_type bits = limbs * chunk_size;
detail::resize_to_bit_size(newval, static_cast<unsigned>(bits), tag_type());
difference_type bit_location = msv_first ? bits - chunk_size : 0;
difference_type bit_location_change = msv_first ? -static_cast<difference_type>(chunk_size) : chunk_size;
while(i != j)
{
detail::assign_bits(newval, static_cast<unsigned_value_type>(*i), static_cast<unsigned>(bit_location), chunk_size, tag_type());
++i;
bit_location += bit_location_change;
}
newval.normalize();
val.backend().swap(newval);
return val;
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
inline typename boost::disable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type
import_bits_fast(
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
{
std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
std::size_t limb_len = byte_len / sizeof(limb_type);
if(byte_len % sizeof(limb_type))
++limb_len;
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data!
result.limbs()[result.size() - 1] = 0u;
std::memcpy(result.limbs(), i, std::min(byte_len, result.size() * sizeof(limb_type)));
result.normalize(); // In case data has leading zeros.
return val;
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
inline typename boost::enable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type
import_bits_fast(
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
{
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
std::size_t limb_len = byte_len / sizeof(result.limbs()[0]);
if(byte_len % sizeof(result.limbs()[0]))
++limb_len;
result.limbs()[0] = 0u;
result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data!
std::memcpy(result.limbs(), i, std::min(byte_len, result.size() * sizeof(result.limbs()[0])));
result.normalize(); // In case data has leading zeros.
return val;
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
import_bits(
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
{
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
import_bits(
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0, bool msv_first = true)
{
#ifdef BOOST_LITTLE_ENDIAN
if(((chunk_size % CHAR_BIT) == 0) && !msv_first)
return detail::import_bits_fast(val, i, j, chunk_size);
#endif
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
}
namespace detail {
template <class Backend>
boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::false_& tag)
{
unsigned limb = location / (sizeof(limb_type) * CHAR_BIT);
unsigned shift = location % (sizeof(limb_type) * CHAR_BIT);
boost::uintmax_t result = 0;
boost::uintmax_t mask = count == std::numeric_limits<boost::uintmax_t>::digits ? ~static_cast<boost::uintmax_t>(0) : (static_cast<boost::uintmax_t>(1u) << count) - 1;
if(count > (sizeof(limb_type) * CHAR_BIT - shift))
{
result = extract_bits(val, location + sizeof(limb_type) * CHAR_BIT - shift, count - sizeof(limb_type) * CHAR_BIT + shift, tag);
result <<= sizeof(limb_type) * CHAR_BIT - shift;
}
if(limb < val.size())
result |= (val.limbs()[limb] >> shift) & mask;
return result;
}
template <class Backend>
inline boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::true_&)
{
boost::uintmax_t result = *val.limbs();
boost::uintmax_t mask = count == std::numeric_limits<boost::uintmax_t>::digits ? ~static_cast<boost::uintmax_t>(0) : (static_cast<boost::uintmax_t>(1u) << count) - 1;
return (result >> location) & mask;
}
}
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class OutputIterator>
OutputIterator export_bits(
const number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, OutputIterator out, unsigned chunk_size, bool msv_first = true)
{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4244)
#endif
typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
if(!val)
{
*out = 0;
++out;
return out;
}
unsigned bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1;
unsigned chunks = bitcount / chunk_size;
if(bitcount % chunk_size)
++chunks;
int bit_location = msv_first ? bitcount - chunk_size : 0;
int bit_step = msv_first ? -static_cast<int>(chunk_size) : chunk_size;
while(bit_location % bit_step) ++bit_location;
do
{
*out = detail::extract_bits(val.backend(), bit_location, chunk_size, tag_type());
++out;
bit_location += bit_step;
} while((bit_location >= 0) && (bit_location < (int)bitcount));
return out;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}
}
}
#endif // BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
+224
View File
@@ -0,0 +1,224 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_LIM_HPP
#define BOOST_MP_CPP_INT_LIM_HPP
namespace std{
namespace detail{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4307)
#endif
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_min(const boost::mpl::true_&, const boost::mpl::true_&)
{
// Bounded and signed.
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> result_type;
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> ui_type;
static const result_type val = -result_type(~ui_type(0));
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_min(const boost::mpl::true_&, const boost::mpl::false_&)
{
// Bounded and unsigned:
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_min(const boost::mpl::false_&, const boost::mpl::true_&)
{
// Unbounded and signed.
// There is no minimum value, just return 0:
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_min(const boost::mpl::false_&, const boost::mpl::false_&)
{
// Unbound and unsigned:
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_max(const boost::mpl::true_&, const boost::mpl::true_&)
{
// Bounded and signed.
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> result_type;
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> ui_type;
static const result_type val = ~ui_type(0);
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_max(const boost::mpl::true_&, const boost::mpl::false_&)
{
// Bound and unsigned:
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> result_type;
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> ui_type;
static const result_type val = ~ui_type(0);
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_max(const boost::mpl::false_&, const boost::mpl::true_&)
{
// Unbounded and signed.
// There is no maximum value, just return 0:
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
return val;
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
get_max(const boost::mpl::false_&, const boost::mpl::false_&)
{
// Unbound and unsigned:
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
return val;
}
}
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
class numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >
{
typedef boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> backend_type;
typedef boost::multiprecision::number<backend_type, ExpressionTemplates> number_type;
struct inititializer
{
inititializer()
{
(std::numeric_limits<number_type>::max)();
(std::numeric_limits<number_type>::min)();
}
void do_nothing()const{}
};
static const inititializer init;
public:
BOOST_STATIC_CONSTEXPR bool is_specialized = true;
//
// Largest and smallest numbers are bounded only by available memory, set
// to zero:
//
static number_type (min)()
{
init.do_nothing();
return detail::get_min<MinBits, MaxBits, SignType, Checked, Allocator, ExpressionTemplates>(boost::multiprecision::backends::is_fixed_precision<backend_type>(), boost::multiprecision::is_signed_number<backend_type>());
}
static number_type (max)()
{
init.do_nothing();
return detail::get_max<MinBits, MaxBits, SignType, Checked, Allocator, ExpressionTemplates>(boost::multiprecision::backends::is_fixed_precision<backend_type>(), boost::multiprecision::is_signed_number<backend_type>());
}
static number_type lowest() { return (min)(); }
BOOST_STATIC_CONSTEXPR int digits = boost::multiprecision::backends::max_precision<backend_type>::value == UINT_MAX ? INT_MAX : boost::multiprecision::backends::max_precision<backend_type>::value;
BOOST_STATIC_CONSTEXPR int digits10 = (digits > INT_MAX / 301) ? (digits / 1000) * 301L : (digits * 301) / 1000;
BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 3;
BOOST_STATIC_CONSTEXPR bool is_signed = boost::multiprecision::is_signed_number<backend_type>::value;
BOOST_STATIC_CONSTEXPR bool is_integer = true;
BOOST_STATIC_CONSTEXPR bool is_exact = true;
BOOST_STATIC_CONSTEXPR int radix = 2;
static number_type epsilon() { return 0; }
static number_type round_error() { return 0; }
BOOST_STATIC_CONSTEXPR int min_exponent = 0;
BOOST_STATIC_CONSTEXPR int min_exponent10 = 0;
BOOST_STATIC_CONSTEXPR int max_exponent = 0;
BOOST_STATIC_CONSTEXPR int max_exponent10 = 0;
BOOST_STATIC_CONSTEXPR bool has_infinity = false;
BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false;
BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false;
BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent;
BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false;
static number_type infinity() { return 0; }
static number_type quiet_NaN() { return 0; }
static number_type signaling_NaN() { return 0; }
static number_type denorm_min() { return 0; }
BOOST_STATIC_CONSTEXPR bool is_iec559 = false;
BOOST_STATIC_CONSTEXPR bool is_bounded = boost::multiprecision::backends::is_fixed_precision<backend_type>::value;
BOOST_STATIC_CONSTEXPR bool is_modulo = (boost::multiprecision::backends::is_fixed_precision<backend_type>::value && (Checked == boost::multiprecision::unchecked));
BOOST_STATIC_CONSTEXPR bool traps = false;
BOOST_STATIC_CONSTEXPR bool tinyness_before = false;
BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero;
};
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
const typename numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::inititializer numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::init;
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::digits;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::digits10;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_digits10;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_signed;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_integer;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_exact;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::radix;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::min_exponent;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::min_exponent10;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_exponent;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_exponent10;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_infinity;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_quiet_NaN;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_signaling_NaN;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_denorm;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_denorm_loss;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_iec559;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_bounded;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_modulo;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::traps;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::tinyness_before;
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::round_style;
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} // namespace std
#endif
+206
View File
@@ -0,0 +1,206 @@
///////////////////////////////////////////////////////////////
// Copyright 2013 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
#ifndef BOOST_MP_CPP_INT_LITERALS_HPP
#define BOOST_MP_CPP_INT_LITERALS_HPP
#include <boost/multiprecision/cpp_int/cpp_int_config.hpp>
namespace boost{ namespace multiprecision{
namespace literals{ namespace detail{
template <char> struct hex_value;
template <> struct hex_value<'0'> { static constexpr limb_type value = 0; };
template <> struct hex_value<'1'> { static constexpr limb_type value = 1; };
template <> struct hex_value<'2'> { static constexpr limb_type value = 2; };
template <> struct hex_value<'3'> { static constexpr limb_type value = 3; };
template <> struct hex_value<'4'> { static constexpr limb_type value = 4; };
template <> struct hex_value<'5'> { static constexpr limb_type value = 5; };
template <> struct hex_value<'6'> { static constexpr limb_type value = 6; };
template <> struct hex_value<'7'> { static constexpr limb_type value = 7; };
template <> struct hex_value<'8'> { static constexpr limb_type value = 8; };
template <> struct hex_value<'9'> { static constexpr limb_type value = 9; };
template <> struct hex_value<'a'> { static constexpr limb_type value = 10; };
template <> struct hex_value<'b'> { static constexpr limb_type value = 11; };
template <> struct hex_value<'c'> { static constexpr limb_type value = 12; };
template <> struct hex_value<'d'> { static constexpr limb_type value = 13; };
template <> struct hex_value<'e'> { static constexpr limb_type value = 14; };
template <> struct hex_value<'f'> { static constexpr limb_type value = 15; };
template <> struct hex_value<'A'> { static constexpr limb_type value = 10; };
template <> struct hex_value<'B'> { static constexpr limb_type value = 11; };
template <> struct hex_value<'C'> { static constexpr limb_type value = 12; };
template <> struct hex_value<'D'> { static constexpr limb_type value = 13; };
template <> struct hex_value<'E'> { static constexpr limb_type value = 14; };
template <> struct hex_value<'F'> { static constexpr limb_type value = 15; };
template <class Pack, limb_type value>
struct combine_value_to_pack;
template <limb_type first, limb_type...ARGS, limb_type value>
struct combine_value_to_pack<value_pack<first, ARGS...>, value>
{
typedef value_pack<first | value, ARGS...> type;
};
template <char NextChar, char...CHARS>
struct pack_values
{
static constexpr unsigned chars_per_limb = sizeof(limb_type) * CHAR_BIT / 4;
static constexpr unsigned shift = ((sizeof...(CHARS)) % chars_per_limb) * 4;
static constexpr limb_type value_to_add = shift ? hex_value<NextChar>::value << shift : hex_value<NextChar>::value;
typedef typename pack_values<CHARS...>::type recursive_packed_type;
typedef typename boost::mpl::if_c<shift == 0,
typename recursive_packed_type::next_type,
recursive_packed_type>::type pack_type;
typedef typename combine_value_to_pack<pack_type, value_to_add>::type type;
};
template <char NextChar>
struct pack_values<NextChar>
{
static constexpr limb_type value_to_add = hex_value<NextChar>::value;
typedef value_pack<value_to_add> type;
};
template <class T>
struct strip_leading_zeros_from_pack;
template <limb_type...PACK>
struct strip_leading_zeros_from_pack<value_pack<PACK...> >
{
typedef value_pack<PACK...> type;
};
template <limb_type...PACK>
struct strip_leading_zeros_from_pack<value_pack<0u, PACK...> >
{
typedef typename strip_leading_zeros_from_pack<value_pack<PACK...> >::type type;
};
template <limb_type v, class PACK>
struct append_value_to_pack;
template <limb_type v, limb_type...PACK>
struct append_value_to_pack<v, value_pack<PACK...> >
{
typedef value_pack<PACK..., v> type;
};
template <class T>
struct reverse_value_pack;
template <limb_type v, limb_type...VALUES>
struct reverse_value_pack<value_pack<v, VALUES...> >
{
typedef typename reverse_value_pack<value_pack<VALUES...> >::type lead_values;
typedef typename append_value_to_pack<v, lead_values>::type type;
};
template <limb_type v>
struct reverse_value_pack<value_pack<v> >
{
typedef value_pack<v> type;
};
template <>
struct reverse_value_pack<value_pack<> >
{
typedef value_pack<> type;
};
template <char l1, char l2, char...STR>
struct make_packed_value_from_str
{
BOOST_STATIC_ASSERT_MSG(l1 == '0', "Multi-precision integer literals must be in hexadecimal notation.");
BOOST_STATIC_ASSERT_MSG((l2 == 'X') || (l2 == 'x'), "Multi-precision integer literals must be in hexadecimal notation.");
typedef typename pack_values<STR...>::type packed_type;
typedef typename strip_leading_zeros_from_pack<packed_type>::type stripped_type;
typedef typename reverse_value_pack<stripped_type>::type type;
};
template <class Pack, class B>
struct make_backend_from_pack
{
static constexpr Pack p = {};
static constexpr B value = p;
};
template <class Pack, class B>
constexpr B make_backend_from_pack<Pack, B>::value;
template <unsigned Digits>
struct signed_cpp_int_literal_result_type
{
static constexpr unsigned bits = Digits * 4;
typedef boost::multiprecision::backends::cpp_int_backend<bits, bits, signed_magnitude, unchecked, void> backend_type;
typedef number<backend_type, et_off> number_type;
};
template <unsigned Digits>
struct unsigned_cpp_int_literal_result_type
{
static constexpr unsigned bits = Digits * 4;
typedef boost::multiprecision::backends::cpp_int_backend<bits, bits, unsigned_magnitude, unchecked, void> backend_type;
typedef number<backend_type, et_off> number_type;
};
}
template <char... STR>
constexpr typename boost::multiprecision::literals::detail::signed_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::number_type operator "" _cppi()
{
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;
return boost::multiprecision::literals::detail::make_backend_from_pack<pt, typename boost::multiprecision::literals::detail::signed_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::backend_type>::value;
}
template <char... STR>
constexpr typename boost::multiprecision::literals::detail::unsigned_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::number_type operator "" _cppui()
{
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;
return boost::multiprecision::literals::detail::make_backend_from_pack<pt, typename boost::multiprecision::literals::detail::unsigned_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::backend_type>::value;
}
#define BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(Bits)\
template <char... STR> \
constexpr boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> > operator "" BOOST_JOIN(_cppi, Bits)()\
{\
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;\
return boost::multiprecision::literals::detail::make_backend_from_pack<\
pt, \
boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> \
>::value;\
}\
template <char... STR> \
constexpr boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void> > operator "" BOOST_JOIN(_cppui, Bits)()\
{\
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;\
return boost::multiprecision::literals::detail::make_backend_from_pack<\
pt, \
boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>\
>::value;\
}\
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(128)
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(256)
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(512)
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(1024)
}
//
// Overload unary minus operator for constexpr use:
//
template <unsigned MinBits, cpp_int_check_type Checked>
constexpr number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>
operator - (const number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>& a)
{
return cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>(a.backend(), boost::multiprecision::literals::detail::make_negate_tag());
}
template <unsigned MinBits, cpp_int_check_type Checked>
constexpr number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>
operator - (number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>&& a)
{
return cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>(static_cast<const number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>&>(a).backend(), boost::multiprecision::literals::detail::make_negate_tag());
}
}} // namespaces
#endif // BOOST_MP_CPP_INT_CORE_HPP
+656
View File
@@ -0,0 +1,656 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_MISC_HPP
#define BOOST_MP_CPP_INT_MISC_HPP
#include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
#include <boost/integer/common_factor_rt.hpp> // gcd/lcm
#include <boost/functional/hash_fwd.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4702)
#pragma warning(disable:4127) // conditional expression is constant
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
#endif
namespace boost{ namespace multiprecision{ namespace backends{
template <class R, class CppInt>
void check_in_range(const CppInt& val, const mpl::int_<checked>&)
{
typedef typename boost::multiprecision::detail::canonical<R, CppInt>::type cast_type;
if(val.sign())
{
if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::min)())) < 0)
BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
}
else
{
if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::max)())) > 0)
BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
}
}
template <class R, class CppInt>
inline void check_in_range(const CppInt& /*val*/, const mpl::int_<unchecked>&) BOOST_NOEXCEPT {}
inline void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {}
inline void check_is_negative(const mpl::false_&)
{
BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
}
template <class Integer>
inline Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT
{
return -i;
}
template <class Integer>
inline Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT
{
return ~(i-1);
}
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
inline typename enable_if_c<is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
typedef mpl::int_<Checked1> checked_type;
check_in_range<R>(backend, checked_type());
*result = static_cast<R>(backend.limbs()[0]);
unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
for(unsigned i = 1; (i < backend.size()) && (shift < static_cast<unsigned>(std::numeric_limits<R>::digits)); ++i)
{
*result += static_cast<R>(backend.limbs()[i]) << shift;
shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
}
if(backend.sign())
{
check_is_negative(boost::is_signed<R>());
*result = negate_integer(*result, boost::is_signed<R>());
}
}
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_MP_NOEXCEPT_IF(is_arithmetic<R>::value)
{
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
*result = static_cast<R>(*p);
for(unsigned i = 1; i < backend.size(); ++i)
{
*result += static_cast<R>(std::ldexp(static_cast<long double>(p[i]), shift));
shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
}
if(backend.sign())
*result = -*result;
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
{
return (val.size() == 1) && (val.limbs()[0] == 0);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
{
return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
result = val;
result.sign(false);
}
//
// Get the location of the least-significant-bit:
//
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, unsigned>::type
eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
{
using default_ops::eval_get_sign;
if(eval_get_sign(a) == 0)
{
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
}
if(a.sign())
{
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
}
//
// Find the index of the least significant limb that is non-zero:
//
unsigned index = 0;
while(!a.limbs()[index] && (index < a.size()))
++index;
//
// Find the index of the least significant bit within that limb:
//
unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
}
//
// Get the location of the most-significant-bit:
//
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, unsigned>::type
eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
{
//
// Find the index of the most significant bit that is non-zero:
//
return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
}
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, unsigned>::type
eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
{
using default_ops::eval_get_sign;
if(eval_get_sign(a) == 0)
{
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
}
if(a.sign())
{
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
}
return eval_msb_imp(a);
}
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, bool>::type
eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
{
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
if(offset >= val.size())
return false;
return val.limbs()[offset] & mask ? true : false;
}
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_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
{
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
if(offset >= val.size())
{
unsigned os = val.size();
val.resize(offset + 1, offset + 1);
if(offset >= val.size())
return; // fixed precision overflow
for(unsigned i = os; i <= offset; ++i)
val.limbs()[i] = 0;
}
val.limbs()[offset] |= mask;
}
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_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
{
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
if(offset >= val.size())
return;
val.limbs()[offset] &= ~mask;
val.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_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
{
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
if(offset >= val.size())
{
unsigned os = val.size();
val.resize(offset + 1, offset + 1);
if(offset >= val.size())
return; // fixed precision overflow
for(unsigned i = os; i <= offset; ++i)
val.limbs()[i] = 0;
}
val.limbs()[offset] ^= mask;
val.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_qr(
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
divide_unsigned_helper(&q, x, y, r);
q.sign(x.sign() != y.sign());
r.sign(x.sign());
}
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_qr(
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
limb_type y,
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
divide_unsigned_helper(&q, x, y, r);
q.sign(x.sign());
r.sign(x.sign());
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
inline typename enable_if_c<is_integral<U>::value>::type eval_qr(
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
U y,
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
using default_ops::eval_qr;
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
t = y;
eval_qr(x, t, q, r);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
inline typename enable_if_c<is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
{
if((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits<limb_type>::max)()))
{
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> d;
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>*>(0), x, static_cast<limb_type>(val), d);
return d.limbs()[0];
}
else
{
return default_ops::eval_integer_modulus(x, val);
}
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
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
eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
{
return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
}
inline limb_type integer_gcd_reduce(limb_type u, limb_type v)
{
do
{
if(u > v)
std::swap(u, v);
if(u == v)
break;
v -= u;
v >>= boost::multiprecision::detail::find_lsb(v);
} while(true);
return u;
}
inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v)
{
do
{
if(u > v)
std::swap(u, v);
if(u == v)
break;
if(v <= ~static_cast<limb_type>(0))
{
u = integer_gcd_reduce(static_cast<limb_type>(v), static_cast<limb_type>(u));
break;
}
v -= u;
#ifdef __MSVC_RUNTIME_CHECKS
while((v & 1u) == 0)
#else
while((static_cast<unsigned>(v) & 1u) == 0)
#endif
v >>= 1;
} while(true);
return u;
}
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_gcd(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
limb_type v)
{
using default_ops::eval_lsb;
using default_ops::eval_is_zero;
using default_ops::eval_get_sign;
int shift;
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a);
int s = eval_get_sign(u);
/* GCD(0,x) := x */
if(s < 0)
{
u.negate();
}
else if(s == 0)
{
result = v;
return;
}
if(v == 0)
{
result = u;
return;
}
/* Let shift := lg K, where K is the greatest power of 2
dividing both u and v. */
unsigned us = eval_lsb(u);
unsigned vs = boost::multiprecision::detail::find_lsb(v);
shift = (std::min)(us, vs);
eval_right_shift(u, us);
if(vs)
v >>= vs;
do
{
/* Now u and v are both odd, so diff(u, v) is even.
Let u = min(u, v), v = diff(u, v)/2. */
if(u.size() <= 2)
{
if(u.size() == 1)
v = integer_gcd_reduce(*u.limbs(), v);
else
{
double_limb_type i;
i = u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
v = static_cast<limb_type>(integer_gcd_reduce(i, static_cast<double_limb_type>(v)));
}
break;
}
eval_subtract(u, v);
us = eval_lsb(u);
eval_right_shift(u, us);
}
while(true);
result = v;
eval_left_shift(result, shift);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
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
eval_gcd(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
const Integer& v)
{
eval_gcd(result, a, static_cast<limb_type>(v));
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
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
eval_gcd(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
const Integer& v)
{
eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
}
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_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)
{
using default_ops::eval_lsb;
using default_ops::eval_is_zero;
using default_ops::eval_get_sign;
if(a.size() == 1)
{
eval_gcd(result, b, *a.limbs());
return;
}
if(b.size() == 1)
{
eval_gcd(result, a, *b.limbs());
return;
}
int shift;
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a), v(b);
int s = eval_get_sign(u);
/* GCD(0,x) := x */
if(s < 0)
{
u.negate();
}
else if(s == 0)
{
result = v;
return;
}
s = eval_get_sign(v);
if(s < 0)
{
v.negate();
}
else if(s == 0)
{
result = u;
return;
}
/* Let shift := lg K, where K is the greatest power of 2
dividing both u and v. */
unsigned us = eval_lsb(u);
unsigned vs = eval_lsb(v);
shift = (std::min)(us, vs);
eval_right_shift(u, us);
eval_right_shift(v, vs);
do
{
/* Now u and v are both odd, so diff(u, v) is even.
Let u = min(u, v), v = diff(u, v)/2. */
s = u.compare(v);
if(s > 0)
u.swap(v);
if(s == 0)
break;
if(v.size() <= 2)
{
if(v.size() == 1)
u = integer_gcd_reduce(*v.limbs(), *u.limbs());
else
{
double_limb_type i, j;
i = v.limbs()[0] | (static_cast<double_limb_type>(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
u = integer_gcd_reduce(i, j);
}
break;
}
eval_subtract(v, u);
vs = eval_lsb(v);
eval_right_shift(v, vs);
}
while(true);
result = u;
eval_left_shift(result, shift);
}
//
// Now again for trivial backends:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
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
{
*result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs());
}
// This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version:
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
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_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs());
result.normalize(); // result may overflow the specified number of bits
}
inline void conversion_overflow(const mpl::int_<checked>&)
{
BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
}
inline void conversion_overflow(const mpl::int_<unchecked>&){}
template <class R, 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
&& is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value
>::type
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
{
typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
{
if(val.isneg())
{
if(static_cast<common_type>(*val.limbs()) > -static_cast<common_type>((std::numeric_limits<R>::min)()))
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
*result = (std::numeric_limits<R>::min)();
}
else
{
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
*result = (std::numeric_limits<R>::max)();
}
}
else
{
*result = static_cast<R>(*val.limbs());
if(val.isneg())
{
check_is_negative(mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>());
*result = negate_integer(*result, mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>());
}
}
}
template <class R, 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
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value
>::type
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
{
typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
{
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
*result = (std::numeric_limits<R>::max)();
}
else
*result = static_cast<R>(*val.limbs());
}
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, unsigned>::type
eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
{
using default_ops::eval_get_sign;
if(eval_get_sign(a) == 0)
{
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
}
if(a.sign())
{
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
}
//
// Find the index of the least significant bit within that limb:
//
return boost::multiprecision::detail::find_lsb(*a.limbs());
}
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, unsigned>::type
eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
{
//
// Find the index of the least significant bit within that limb:
//
return boost::multiprecision::detail::find_msb(*a.limbs());
}
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, unsigned>::type
eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
{
using default_ops::eval_get_sign;
if(eval_get_sign(a) == 0)
{
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
}
if(a.sign())
{
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
}
return eval_msb_imp(a);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
inline std::size_t hash_value(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
{
std::size_t result = 0;
for(unsigned i = 0; i < val.size(); ++i)
{
boost::hash_combine(result, val.limbs()[i]);
}
boost::hash_combine(result, val.sign());
return result;
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}}} // namespaces
#endif
+490
View File
@@ -0,0 +1,490 @@
///////////////////////////////////////////////////////////////
// Copyright 2012 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
//
// Comparison operators for cpp_int_backend:
//
#ifndef BOOST_MP_CPP_INT_MUL_HPP
#define BOOST_MP_CPP_INT_MUL_HPP
namespace boost{ namespace multiprecision{ namespace backends{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127) // conditional expression is constant
#endif
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 >::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(!val)
{
result = static_cast<limb_type>(0);
return;
}
if((void*)&a != (void*)&result)
result.resize(a.size(), a.size());
double_limb_type carry = 0;
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
while(p != pe)
{
carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
#ifdef __MSVC_RUNTIME_CHECKS
*p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
*p = static_cast<limb_type>(carry);
#endif
carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
++p, ++pa;
}
if(carry)
{
unsigned i = result.size();
result.resize(i + 1, i + 1);
if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (result.size() > i))
result.limbs()[i] = static_cast<limb_type>(carry);
}
result.sign(a.sign());
if(!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable)
result.normalize();
}
//
// resize_for_carry forces a resize of the underlying buffer only if a previous request
// for "required" elements could possibly have failed, *and* we have checking enabled.
// This will cause an overflow error inside resize():
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/){}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, void>& result, unsigned required)
{
if(result.size() != required)
result.resize(required, required);
}
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, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
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_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
// Very simple long multiplication, only usable for small numbers of limb_type's
// but that's the typical use case for this type anyway:
//
// Special cases first:
//
unsigned as = a.size();
unsigned bs = b.size();
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
if(as == 1)
{
bool s = b.sign() != a.sign();
if(bs == 1)
{
result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
}
else
{
limb_type l = *pa;
eval_multiply(result, b, l);
}
result.sign(s);
return;
}
if(bs == 1)
{
bool s = b.sign() != a.sign();
limb_type l = *pb;
eval_multiply(result, a, l);
result.sign(s);
return;
}
if((void*)&result == (void*)&a)
{
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
eval_multiply(result, t, b);
return;
}
if((void*)&result == (void*)&b)
{
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
eval_multiply(result, a, t);
return;
}
result.resize(as + bs, as + bs - 1);
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
static const double_limb_type limb_max = ~static_cast<limb_type>(0u);
static const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u);
BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max);
double_limb_type carry = 0;
std::memset(pr, 0, result.size() * sizeof(limb_type));
for(unsigned i = 0; i < as; ++i)
{
unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
for(unsigned j = 0; j < inner_limit; ++j)
{
BOOST_ASSERT(i+j < result.size());
#if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized
|| ((std::numeric_limits<double_limb_type>::max)() - carry
>
static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value) * static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value)));
#endif
carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j]));
carry += pr[i + j];
#ifdef __MSVC_RUNTIME_CHECKS
pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
#else
pr[i + j] = static_cast<limb_type>(carry);
#endif
carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
}
resize_for_carry(result, as + bs); // May throw if checking is enabled
if(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable || (i + bs < result.size()))
pr[i + bs] = static_cast<limb_type>(carry);
carry = 0;
}
result.normalize();
//
// Set the sign of the result:
//
result.sign(a.sign() != b.sign());
}
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>
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
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
eval_multiply(result, result, a);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
eval_multiply(result, result, val);
}
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>
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
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(val <= (std::numeric_limits<limb_type>::max)())
{
eval_multiply(result, a, static_cast<limb_type>(val));
}
else
{
#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
#else
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
t = val;
#endif
eval_multiply(result, a, t);
}
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
eval_multiply(result, result, val);
}
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>
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
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(val > 0)
eval_multiply(result, a, static_cast<limb_type>(val));
else
{
eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
result.negate();
}
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
eval_multiply(result, result, val);
}
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 >::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
if(val > 0)
{
if(val <= (std::numeric_limits<limb_type>::max)())
{
eval_multiply(result, a, static_cast<limb_type>(val));
return;
}
}
else if(val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
{
eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
result.negate();
return;
}
#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
#else
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
t = val;
#endif
eval_multiply(result, a, t);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
eval_multiply(result, result, val);
}
//
// Now over again for trivial cpp_int's:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.sign(result.sign() != o.sign());
result.normalize();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
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<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
>::type
eval_multiply(
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_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.sign(a.sign() != b.sign());
result.normalize();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_multiply(
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_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
{
*result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
result.normalize();
}
//
// Special routines for multiplying two integers to obtain a multiprecision result:
//
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
signed_double_limb_type a, signed_double_limb_type b)
{
static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
bool s = false;
double_limb_type w, x, y, z;
if(a < 0)
{
a = -a;
s = true;
}
if(b < 0)
{
b = -b;
s = !s;
}
w = a & mask;
x = a >> limb_bits;
y = b & mask;
z = b >> limb_bits;
result.resize(4, 4);
limb_type* pr = result.limbs();
double_limb_type carry = w * y;
#ifdef __MSVC_RUNTIME_CHECKS
pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
carry >>= limb_bits;
carry += w * z + x * y;
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
carry >>= limb_bits;
carry += x * z;
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
pr[3] = static_cast<limb_type>(carry >> limb_bits);
#else
pr[0] = static_cast<limb_type>(carry);
carry >>= limb_bits;
carry += w * z + x * y;
pr[1] = static_cast<limb_type>(carry);
carry >>= limb_bits;
carry += x * z;
pr[2] = static_cast<limb_type>(carry);
pr[3] = static_cast<limb_type>(carry >> limb_bits);
#endif
result.sign(s);
result.normalize();
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
BOOST_MP_FORCEINLINE typename enable_if_c<
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
double_limb_type a, double_limb_type b)
{
static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
double_limb_type w, x, y, z;
w = a & mask;
x = a >> limb_bits;
y = b & mask;
z = b >> limb_bits;
result.resize(4, 4);
limb_type* pr = result.limbs();
double_limb_type carry = w * y;
#ifdef __MSVC_RUNTIME_CHECKS
pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
carry >>= limb_bits;
carry += w * z;
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
carry >>= limb_bits;
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
carry = x * y + pr[1];
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
carry >>= limb_bits;
carry += pr[2] + x * z;
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
pr[3] = static_cast<limb_type>(carry >> limb_bits);
#else
pr[0] = static_cast<limb_type>(carry);
carry >>= limb_bits;
carry += w * z;
pr[1] = static_cast<limb_type>(carry);
carry >>= limb_bits;
pr[2] = static_cast<limb_type>(carry);
carry = x * y + pr[1];
pr[1] = static_cast<limb_type>(carry);
carry >>= limb_bits;
carry += pr[2] + x * z;
pr[2] = static_cast<limb_type>(carry);
pr[3] = static_cast<limb_type>(carry >> limb_bits);
#endif
result.sign(false);
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>
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
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
{
typedef typename boost::multiprecision::detail::canonical<typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::local_limb_type, cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::type canonical_type;
eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
result.sign(a.sign() != b.sign());
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
SI a, SI b)
{
result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
}
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
eval_multiply(
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
UI a, UI b)
{
result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}}} // namespaces
#endif
+199
View File
@@ -0,0 +1,199 @@
///////////////////////////////////////////////////////////////
// Copyright 2013 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
#ifndef BOOST_MP_CPP_INT_SERIALIZE_HPP
#define BOOST_MP_CPP_INT_SERIALIZE_HPP
namespace boost {
namespace archive{
class binary_oarchive;
class binary_iarchive;
}
namespace serialization {
namespace mp = boost::multiprecision;
namespace cpp_int_detail{
using namespace boost::multiprecision;
using namespace boost::multiprecision::backends;
template <class T>
struct is_binary_archive : public mpl::false_ {};
template <>
struct is_binary_archive<boost::archive::binary_oarchive> : public mpl::true_ {};
template <>
struct is_binary_archive<boost::archive::binary_iarchive> : public mpl::true_ {};
//
// We have 8 serialization methods to fill out (and test), they are all permutations of:
// Load vs Store.
// Trivial or non-trivial cpp_int type.
// Binary or not archive.
//
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, mpl::false_ const&)
{
// Load.
// Non-trivial.
// Non binary.
bool s;
ar & s;
std::size_t limb_count;
std::size_t byte_count;
ar & byte_count;
limb_count = byte_count / sizeof(limb_type) + ((byte_count % sizeof(limb_type)) ? 1 : 0);
val.resize(limb_count, limb_count);
limb_type* pl = val.limbs();
for(std::size_t i = 0; i < limb_count; ++i)
{
pl[i] = 0;
for(std::size_t j = 0; (j < sizeof(limb_type)) && byte_count; ++j)
{
unsigned char byte;
ar & byte;
pl[i] |= static_cast<limb_type>(byte) << (j * CHAR_BIT);
--byte_count;
}
}
if(s != val.sign())
val.negate();
val.normalize();
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, mpl::false_ const&)
{
// Store.
// Non-trivial.
// Non binary.
bool s = val.sign();
ar & s;
limb_type* pl = val.limbs();
std::size_t limb_count = val.size();
std::size_t byte_count = limb_count * sizeof(limb_type);
ar & byte_count;
for(std::size_t i = 0; i < limb_count; ++i)
{
limb_type l = pl[i];
for(std::size_t j = 0; j < sizeof(limb_type); ++j)
{
unsigned char byte = static_cast<unsigned char>((l >> (j * CHAR_BIT)) & ((1u << CHAR_BIT) - 1));
ar & byte;
}
}
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, mpl::false_ const&)
{
// Load.
// Trivial.
// Non binary.
bool s;
typename Int::local_limb_type l = 0;
ar & s;
std::size_t byte_count;
ar & byte_count;
for(std::size_t i = 0; i < byte_count; ++i)
{
unsigned char b;
ar & b;
l |= static_cast<typename Int::local_limb_type>(b) << (i * CHAR_BIT);
}
*val.limbs() = l;
if(s != val.sign())
val.negate();
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, mpl::false_ const&)
{
// Store.
// Trivial.
// Non binary.
bool s = val.sign();
typename Int::local_limb_type l = *val.limbs();
ar & s;
std::size_t limb_count = sizeof(l);
ar & limb_count;
for(std::size_t i = 0; i < limb_count; ++i)
{
unsigned char b = static_cast<unsigned char>(static_cast<typename Int::local_limb_type>(l >> (i * CHAR_BIT)) & static_cast<typename Int::local_limb_type>((1u << CHAR_BIT) - 1));
ar & b;
}
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, mpl::true_ const&)
{
// Load.
// Non-trivial.
// Binary.
bool s;
std::size_t c;
ar & s;
ar & c;
val.resize(c, c);
ar.load_binary(val.limbs(), c * sizeof(limb_type));
if(s != val.sign())
val.negate();
val.normalize();
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, mpl::true_ const&)
{
// Store.
// Non-trivial.
// Binary.
bool s = val.sign();
std::size_t c = val.size();
ar & s;
ar & c;
ar.save_binary(val.limbs(), c * sizeof(limb_type));
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, mpl::true_ const&)
{
// Load.
// Trivial.
// Binary.
bool s;
ar & s;
ar.load_binary(val.limbs(), sizeof(*val.limbs()));
if(s != val.sign())
val.negate();
}
template <class Archive, class Int>
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, mpl::true_ const&)
{
// Store.
// Trivial.
// Binary.
bool s = val.sign();
ar & s;
ar.save_binary(val.limbs(), sizeof(*val.limbs()));
}
}
template<class Archive, unsigned MinBits, unsigned MaxBits, mp::cpp_integer_type SignType, mp::cpp_int_check_type Checked, class Allocator>
void serialize(Archive & ar, mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& val, const unsigned int /*version*/)
{
typedef typename Archive::is_saving save_tag;
typedef mpl::bool_<mp::backends::is_trivial_cpp_int<mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value> trivial_tag;
typedef typename cpp_int_detail::is_binary_archive<Archive>::type binary_tag;
// Just dispatch to the correct method:
cpp_int_detail::do_serialize(ar, val, save_tag(), trivial_tag(), binary_tag());
}
}} // namespaces
#endif // BOOST_MP_CPP_INT_SERIALIZE_HPP
@@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////
// Copyright 2013 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
#ifndef BOOST_MP_CPP_INT_VP_HPP
#define BOOST_MP_CPP_INT_VP_HPP
namespace boost{ namespace multiprecision{
namespace literals{ namespace detail{
template <limb_type...VALUES>
struct value_pack
{
constexpr value_pack(){}
typedef value_pack<0, VALUES...> next_type;
};
template <class T>
struct is_value_pack{ static constexpr bool value = false; };
template <limb_type...VALUES>
struct is_value_pack<value_pack<VALUES...> >{ static constexpr bool value = true; };
struct negate_tag{};
constexpr negate_tag make_negate_tag()
{
return negate_tag();
}
}}}} // namespaces
#endif // BOOST_MP_CPP_INT_CORE_HPP