mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-01 13:07:52 +00:00
Added thirdparty: boost library
This commit is contained in:
+368
@@ -0,0 +1,368 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_ADD_HPP
|
||||
#define BOOST_MP_CPP_INT_ADD_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/constexpr.hpp>
|
||||
#include <boost/multiprecision/cpp_int/add_unsigned.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends {
|
||||
|
||||
//
|
||||
// As above, but for adding a single limb to a non-trivial cpp_int:
|
||||
//
|
||||
template <class CppInt1, class CppInt2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const limb_type& o) noexcept(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();
|
||||
std::size_t 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)
|
||||
{
|
||||
std_constexpr::copy(pa + i, pa + a.size(), pr + i);
|
||||
}
|
||||
if (carry)
|
||||
{
|
||||
// We overflowed, need to add one more limb:
|
||||
std::size_t x = result.size();
|
||||
result.resize(x + 1, x + 1);
|
||||
if (result.size() > x)
|
||||
result.limbs()[x] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
}
|
||||
//
|
||||
// And again to subtract a single limb:
|
||||
//
|
||||
template <class CppInt1, class CppInt2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const limb_type& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
// Subtract one limb.
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
constexpr 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)
|
||||
{
|
||||
std_constexpr::copy(pa + 1, pa + a.size(), pr + 1);
|
||||
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);
|
||||
std::size_t i = 1;
|
||||
while (!pa[i])
|
||||
{
|
||||
pr[i] = CppInt1::max_limb_value;
|
||||
++i;
|
||||
}
|
||||
pr[i] = pa[i] - 1;
|
||||
if (&result != &a)
|
||||
{
|
||||
++i;
|
||||
std_constexpr::copy(pa + i, pa + a.size(), pr + i);
|
||||
}
|
||||
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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_add(result, result, o);
|
||||
}
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
constexpr 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];
|
||||
if (!result.limbs()[0] && (result.size() == 1))
|
||||
result.sign(false);
|
||||
}
|
||||
else
|
||||
eval_add(result, one);
|
||||
}
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
constexpr 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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_subtract(result, result, o);
|
||||
}
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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();
|
||||
}
|
||||
|
||||
}}} // namespace boost::multiprecision::backends
|
||||
|
||||
#endif
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2020 Madhur Chauhan.
|
||||
// Copyright 2020 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_MP_ADD_UNSIGNED_HPP
|
||||
#define BOOST_MP_ADD_UNSIGNED_HPP
|
||||
|
||||
#include <boost/multiprecision/cpp_int/intel_intrinsics.hpp>
|
||||
#include <boost/multiprecision/detail/assert.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends {
|
||||
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned_constexpr(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
using ::boost::multiprecision::std_constexpr::swap;
|
||||
//
|
||||
// This is the generic, C++ only version of addition.
|
||||
// It's also used for all constexpr branches, hence the name.
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
//
|
||||
double_limb_type carry = 0;
|
||||
std::size_t m(0), x(0);
|
||||
std::size_t as = a.size();
|
||||
std::size_t 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)
|
||||
std_constexpr::copy(pa, pa + (pr_end - pr), pr);
|
||||
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 (result.size() > x)
|
||||
result.limbs()[x] = static_cast<limb_type>(1u);
|
||||
}
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
}
|
||||
//
|
||||
// Core subtraction routine for all non-trivial cpp_int's:
|
||||
//
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned_constexpr(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
using ::boost::multiprecision::std_constexpr::swap;
|
||||
//
|
||||
// This is the generic, C++ only version of subtraction.
|
||||
// It's also used for all constexpr branches, hence the name.
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
//
|
||||
double_limb_type borrow = 0;
|
||||
std::size_t m(0), x(0);
|
||||
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)
|
||||
{
|
||||
::boost::multiprecision::std_constexpr::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;
|
||||
}
|
||||
|
||||
std::size_t 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))
|
||||
std_constexpr::copy(pa + i, pa + x, pr + i);
|
||||
BOOST_MP_ASSERT(0 == borrow);
|
||||
|
||||
//
|
||||
// We may have lost digits, if so update limb usage count:
|
||||
//
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
if (swapped)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_MP_HAS_IMMINTRIN_H
|
||||
//
|
||||
// This is the key addition routine where all the argument types are non-trivial cpp_int's:
|
||||
//
|
||||
//
|
||||
// This optimization is limited to: GCC, LLVM, ICC (Intel), MSVC for x86_64 and i386.
|
||||
// If your architecture and compiler supports ADC intrinsic, please file a bug
|
||||
//
|
||||
// As of May, 2020 major compilers don't recognize carry chain though adc
|
||||
// intrinsics are used to hint compilers to use ADC and still compilers don't
|
||||
// unroll the loop efficiently (except LLVM) so manual unrolling is done.
|
||||
//
|
||||
// Also note that these intrinsics were only introduced by Intel as part of the
|
||||
// ADX processor extensions, even though the addc instruction has been available
|
||||
// for basically all x86 processors. That means gcc-9, clang-9, msvc-14.2 and up
|
||||
// are required to support these intrinsics.
|
||||
//
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(a.size()))
|
||||
{
|
||||
add_unsigned_constexpr(result, a, b);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
std::size_t m(0), x(0);
|
||||
std::size_t as = a.size();
|
||||
std::size_t 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();
|
||||
|
||||
if (as < bs)
|
||||
swap(pa, pb);
|
||||
// First where a and b overlap:
|
||||
std::size_t i = 0;
|
||||
unsigned char carry = 0;
|
||||
#if defined(BOOST_MSVC) && !defined(BOOST_HAS_INT128) && defined(_M_X64)
|
||||
//
|
||||
// Special case for 32-bit limbs on 64-bit architecture - we can process
|
||||
// 2 limbs with each instruction.
|
||||
//
|
||||
for (; i + 8 <= m; i += 8)
|
||||
{
|
||||
carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 0), *(unsigned long long*)(pb + i + 0), (unsigned long long*)(pr + i));
|
||||
carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 2), *(unsigned long long*)(pb + i + 2), (unsigned long long*)(pr + i + 2));
|
||||
carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 4), *(unsigned long long*)(pb + i + 4), (unsigned long long*)(pr + i + 4));
|
||||
carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 6), *(unsigned long long*)(pb + i + 6), (unsigned long long*)(pr + i + 6));
|
||||
}
|
||||
#else
|
||||
for (; i + 4 <= m; i += 4)
|
||||
{
|
||||
carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 0], pb[i + 0], pr + i);
|
||||
carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 1], pb[i + 1], pr + i + 1);
|
||||
carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 2], pb[i + 2], pr + i + 2);
|
||||
carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 3], pb[i + 3], pr + i + 3);
|
||||
}
|
||||
#endif
|
||||
for (; i < m; ++i)
|
||||
carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i], pb[i], pr + i);
|
||||
for (; i < x && carry; ++i)
|
||||
// We know carry is 1, so we just need to increment pa[i] (ie add a literal 1) and capture the carry:
|
||||
carry = ::boost::multiprecision::detail::addcarry_limb(0, pa[i], 1, pr + i);
|
||||
if (i == x && carry)
|
||||
{
|
||||
// We overflowed, need to add one more limb:
|
||||
result.resize(x + 1, x + 1);
|
||||
if (result.size() > x)
|
||||
result.limbs()[x] = static_cast<limb_type>(1u);
|
||||
}
|
||||
else if ((x != i) && (pa != pr))
|
||||
// Copy remaining digits only if we need to:
|
||||
std_constexpr::copy(pa + i, pa + x, pr + i);
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
}
|
||||
}
|
||||
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(a.size()))
|
||||
{
|
||||
subtract_unsigned_constexpr(result, a, b);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
std::size_t m(0), x(0);
|
||||
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)
|
||||
{
|
||||
::boost::multiprecision::std_constexpr::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;
|
||||
}
|
||||
|
||||
std::size_t i = 0;
|
||||
unsigned char borrow = 0;
|
||||
// First where a and b overlap:
|
||||
#if defined(BOOST_MSVC) && !defined(BOOST_HAS_INT128) && defined(_M_X64)
|
||||
//
|
||||
// Special case for 32-bit limbs on 64-bit architecture - we can process
|
||||
// 2 limbs with each instruction.
|
||||
//
|
||||
for (; i + 8 <= m; i += 8)
|
||||
{
|
||||
borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i), *reinterpret_cast<const unsigned long long*>(pb + i), reinterpret_cast<unsigned long long*>(pr + i));
|
||||
borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i + 2), *reinterpret_cast<const unsigned long long*>(pb + i + 2), reinterpret_cast<unsigned long long*>(pr + i + 2));
|
||||
borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i + 4), *reinterpret_cast<const unsigned long long*>(pb + i + 4), reinterpret_cast<unsigned long long*>(pr + i + 4));
|
||||
borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i + 6), *reinterpret_cast<const unsigned long long*>(pb + i + 6), reinterpret_cast<unsigned long long*>(pr + i + 6));
|
||||
}
|
||||
#else
|
||||
for(; i + 4 <= m; i += 4)
|
||||
{
|
||||
borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i], pb[i], pr + i);
|
||||
borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i + 1], pb[i + 1], pr + i + 1);
|
||||
borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i + 2], pb[i + 2], pr + i + 2);
|
||||
borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i + 3], pb[i + 3], pr + i + 3);
|
||||
}
|
||||
#endif
|
||||
for (; i < m; ++i)
|
||||
borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i], pb[i], pr + i);
|
||||
|
||||
// Now where only a has digits, only as long as we've borrowed:
|
||||
while (borrow && (i < x))
|
||||
{
|
||||
borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i], 0, pr + i);
|
||||
++i;
|
||||
}
|
||||
// Any remaining digits are the same as those in pa:
|
||||
if ((x != i) && (pa != pr))
|
||||
std_constexpr::copy(pa + i, pa + x, pr + i);
|
||||
BOOST_MP_ASSERT(0 == borrow);
|
||||
|
||||
//
|
||||
// We may have lost digits, if so update limb usage count:
|
||||
//
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
if (swapped)
|
||||
result.negate();
|
||||
} // constepxr.
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
add_unsigned_constexpr(result, a, b);
|
||||
}
|
||||
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
subtract_unsigned_constexpr(result, a, b);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} } } // namespaces
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+889
@@ -0,0 +1,889 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_BITWISE_HPP
|
||||
#define BOOST_MP_CPP_INT_BITWISE_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <boost/multiprecision/detail/endian.hpp>
|
||||
#include <boost/multiprecision/detail/no_exceptions_support.hpp>
|
||||
#include <boost/multiprecision/detail/assert.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4319)
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends {
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_CXX14_CONSTEXPR 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 std::integral_constant<int, checked>&)
|
||||
{
|
||||
if (result.sign() || o.sign())
|
||||
BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&, const std::integral_constant<int, unchecked>&) {}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const std::integral_constant<int, checked>&)
|
||||
{
|
||||
if (result.sign())
|
||||
BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const std::integral_constant<int, checked>&) {}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const std::integral_constant<int, unchecked>&) {}
|
||||
|
||||
template <class CppInt1, class CppInt2, class Op>
|
||||
BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
|
||||
CppInt1& result,
|
||||
const CppInt2& o,
|
||||
Op op, const std::integral_constant<bool, true>&) noexcept((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:
|
||||
//
|
||||
std::size_t rs = result.size();
|
||||
std::size_t os = o.size();
|
||||
std::size_t m(0), x(0);
|
||||
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 (std::size_t i = rs; i < x; ++i)
|
||||
pr[i] = 0;
|
||||
|
||||
limb_type next_limb = 0;
|
||||
|
||||
if (!result.sign())
|
||||
{
|
||||
if (!o.sign())
|
||||
{
|
||||
for (std::size_t i = 0; i < os; ++i)
|
||||
pr[i] = op(pr[i], po[i]);
|
||||
for (std::size_t i = os; i < x; ++i)
|
||||
pr[i] = op(pr[i], limb_type(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// "o" is negative:
|
||||
double_limb_type carry = 1;
|
||||
for (std::size_t 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 (std::size_t 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 (std::size_t 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 (std::size_t 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 (std::size_t 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 (std::size_t 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 (std::size_t 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>
|
||||
BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
|
||||
CppInt1& result,
|
||||
const CppInt2& o,
|
||||
Op op, const std::integral_constant<bool, false>&) noexcept((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:
|
||||
//
|
||||
std::size_t rs = result.size();
|
||||
std::size_t os = o.size();
|
||||
std::size_t m(0), x(0);
|
||||
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 (std::size_t i = rs; i < x; ++i)
|
||||
pr[i] = 0;
|
||||
|
||||
for (std::size_t i = 0; i < os; ++i)
|
||||
pr[i] = op(pr[i], po[i]);
|
||||
for (std::size_t i = os; i < x; ++i)
|
||||
pr[i] = op(pr[i], limb_type(0));
|
||||
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
struct bit_and
|
||||
{
|
||||
BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a & b; }
|
||||
};
|
||||
struct bit_or
|
||||
{
|
||||
BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a | b; }
|
||||
};
|
||||
struct bit_xor
|
||||
{
|
||||
BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a ^ b; }
|
||||
};
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
bitwise_op(result, o, bit_and(),
|
||||
std::integral_constant<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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
bitwise_op(result, o, bit_or(),
|
||||
std::integral_constant<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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
bitwise_op(result, o, bit_xor(),
|
||||
std::integral_constant<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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept
|
||||
{
|
||||
result.limbs()[0] &= l;
|
||||
result.resize(1, 1);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept
|
||||
{
|
||||
result.limbs()[0] |= l;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept
|
||||
{
|
||||
result.limbs()[0] ^= l;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
static_assert(((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
std::size_t os = o.size();
|
||||
result.resize(SIZE_MAX, os);
|
||||
for (std::size_t i = 0; i < os; ++i)
|
||||
result.limbs()[i] = ~o.limbs()[i];
|
||||
for (std::size_t 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);
|
||||
std::size_t ors = result.size();
|
||||
if ((ors == 1) && (!*result.limbs()))
|
||||
return; // shifting zero yields zero.
|
||||
std::size_t 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 BOOST_MP_CXX14_CONSTEXPR 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);
|
||||
|
||||
std::size_t ors = result.size();
|
||||
if ((ors == 1) && (!*result.limbs()))
|
||||
return; // shifting zero yields zero.
|
||||
std::size_t 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;
|
||||
}
|
||||
|
||||
std::size_t i = rs - result.size();
|
||||
for (; i < ors; ++i)
|
||||
pr[rs - 1 - i] = pr[ors - 1 - i];
|
||||
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
{
|
||||
for (; i < rs; ++i)
|
||||
pr[rs - 1 - i] = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
std::memset(pr, 0, (rs - i) * sizeof(*pr));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR 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);
|
||||
|
||||
std::size_t ors = result.size();
|
||||
if ((ors == 1) && (!*result.limbs()))
|
||||
return; // shifting zero yields zero.
|
||||
std::size_t 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;
|
||||
}
|
||||
|
||||
std::size_t i = rs - result.size();
|
||||
// This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
|
||||
BOOST_MP_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 (; rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(2u) + offset); ++i)
|
||||
{
|
||||
pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
|
||||
pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift);
|
||||
}
|
||||
if (rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(1u) + offset))
|
||||
{
|
||||
pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
|
||||
++i;
|
||||
}
|
||||
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
{
|
||||
for (; i < rs; ++i)
|
||||
pr[rs - 1 - i] = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
std::memset(pr, 0, (rs - i) * sizeof(*pr));
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
|
||||
constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
|
||||
constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
|
||||
if ((s & limb_shift_mask) == 0)
|
||||
{
|
||||
left_shift_limb(result, s);
|
||||
}
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
else if ((s & byte_shift_mask) == 0)
|
||||
#else
|
||||
else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
#endif
|
||||
{
|
||||
left_shift_byte(result, s);
|
||||
}
|
||||
#elif BOOST_MP_ENDIAN_LITTLE_BYTE
|
||||
constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if ((s & byte_shift_mask) == 0)
|
||||
#else
|
||||
constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
|
||||
left_shift_limb(result, s);
|
||||
else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
#endif
|
||||
{
|
||||
left_shift_byte(result, s);
|
||||
}
|
||||
#else
|
||||
constexpr 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);
|
||||
BOOST_MP_ASSERT((s % CHAR_BIT) == 0);
|
||||
std::size_t ors = result.size();
|
||||
std::size_t 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);
|
||||
limb_type 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 BOOST_MP_CXX14_CONSTEXPR void right_shift_limb(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
BOOST_MP_ASSERT((s % Int::limb_bits) == 0);
|
||||
std::size_t ors = result.size();
|
||||
std::size_t rs = ors;
|
||||
if (offset >= rs)
|
||||
{
|
||||
result = limb_type(0);
|
||||
return;
|
||||
}
|
||||
rs -= offset;
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
std::size_t i = 0;
|
||||
for (; i < rs; ++i)
|
||||
pr[i] = pr[i + offset];
|
||||
result.resize(rs, rs);
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR 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);
|
||||
std::size_t ors = result.size();
|
||||
std::size_t 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;
|
||||
}
|
||||
}
|
||||
std::size_t i = 0;
|
||||
|
||||
// This code only works for non-zero shift, otherwise we invoke undefined behaviour!
|
||||
BOOST_MP_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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
|
||||
constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
|
||||
if ((s & limb_shift_mask) == 0)
|
||||
right_shift_limb(result, s);
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
else if ((s & byte_shift_mask) == 0)
|
||||
#else
|
||||
else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
#endif
|
||||
right_shift_byte(result, s);
|
||||
#elif BOOST_MP_ENDIAN_LITTLE_BYTE
|
||||
constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if ((s & byte_shift_mask) == 0)
|
||||
#else
|
||||
constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
|
||||
right_shift_limb(result, s);
|
||||
else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
#endif
|
||||
right_shift_byte(result, s);
|
||||
#else
|
||||
constexpr 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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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 BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
|
||||
constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
|
||||
if ((s & limb_shift_mask) == 0)
|
||||
right_shift_limb(result, s);
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
else if ((s & byte_shift_mask) == 0)
|
||||
#else
|
||||
else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
#endif
|
||||
right_shift_byte(result, s);
|
||||
#elif BOOST_MP_ENDIAN_LITTLE_BYTE
|
||||
constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if ((s & byte_shift_mask) == 0)
|
||||
#else
|
||||
constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
|
||||
right_shift_limb(result, s);
|
||||
else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
|
||||
#endif
|
||||
right_shift_byte(result, s);
|
||||
#else
|
||||
constexpr 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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<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, T s) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
|
||||
eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
static_assert(((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = ~*o.limbs();
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() &= *o.limbs();
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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())
|
||||
{
|
||||
constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() |= *o.limbs();
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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())
|
||||
{
|
||||
constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() ^= *o.limbs();
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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())
|
||||
{
|
||||
constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::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();
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace boost::multiprecision::backends
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_CHECKED_HPP
|
||||
#define BOOST_MP_CPP_INT_CHECKED_HPP
|
||||
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/multiprecision/detail/standalone_config.hpp>
|
||||
#include <boost/multiprecision/detail/no_exceptions_support.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.
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T type_max() noexcept
|
||||
{
|
||||
return
|
||||
#ifdef BOOST_HAS_INT128
|
||||
std::is_same<T, boost::multiprecision::int128_type>::value ? INT128_MAX :
|
||||
std::is_same<T, boost::multiprecision::uint128_type>::value ? UINT128_MAX :
|
||||
#endif
|
||||
(std::numeric_limits<T>::max)();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T type_min() noexcept
|
||||
{
|
||||
return
|
||||
#ifdef BOOST_HAS_INT128
|
||||
std::is_same<T, boost::multiprecision::int128_type>::value ? INT128_MIN :
|
||||
std::is_same<T, boost::multiprecision::uint128_type>::value ? T(0) :
|
||||
#endif
|
||||
(std::numeric_limits<T>::min)();
|
||||
}
|
||||
|
||||
inline void raise_overflow(std::string op)
|
||||
{
|
||||
BOOST_MP_THROW_EXCEPTION(std::overflow_error("overflow in " + op));
|
||||
}
|
||||
inline void raise_add_overflow()
|
||||
{
|
||||
raise_overflow("addition");
|
||||
}
|
||||
inline void raise_subtract_overflow()
|
||||
{
|
||||
BOOST_MP_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 BOOST_MP_CXX14_CONSTEXPR A checked_add_imp(A a, A b, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
if (a > 0)
|
||||
{
|
||||
if ((b > 0) && ((type_max<A>() - b) < a))
|
||||
raise_add_overflow();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((b < 0) && ((type_min<A>() - b) > a))
|
||||
raise_add_overflow();
|
||||
}
|
||||
return a + b;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_add_imp(A a, A b, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
if ((type_max<A>() - b) < a)
|
||||
raise_add_overflow();
|
||||
return a + b;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_add(A a, A b, const std::integral_constant<int, checked>&)
|
||||
{
|
||||
return checked_add_imp(a, b, std::integral_constant<bool, boost::multiprecision::detail::is_signed<A>::value && boost::multiprecision::detail::is_integral<A>::value > ());
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_add(A a, A b, const std::integral_constant<int, unchecked>&)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract_imp(A a, A b, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
if (a > 0)
|
||||
{
|
||||
if ((b < 0) && ((type_max<A>() + b) < a))
|
||||
raise_subtract_overflow();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((b > 0) && ((type_min<A>() + b) > a))
|
||||
raise_subtract_overflow();
|
||||
}
|
||||
return a - b;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract_imp(A a, A b, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
if (a < b)
|
||||
raise_subtract_overflow();
|
||||
return a - b;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract(A a, A b, const std::integral_constant<int, checked>&)
|
||||
{
|
||||
return checked_subtract_imp(a, b, std::integral_constant<bool, boost::multiprecision::detail::is_signed<A>::value && boost::multiprecision::detail::is_integral<A>::value>());
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract(A a, A b, const std::integral_constant<int, unchecked>&)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_multiply(A a, A b, const std::integral_constant<int, checked>&)
|
||||
{
|
||||
BOOST_MP_USING_ABS
|
||||
if (a && (type_max<A>() / abs(a) < abs(b)))
|
||||
raise_mul_overflow();
|
||||
return a * b;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_multiply(A a, A b, const std::integral_constant<int, unchecked>&)
|
||||
{
|
||||
return a * b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_divide(A a, A b, const std::integral_constant<int, checked>&)
|
||||
{
|
||||
if (b == 0)
|
||||
raise_div_overflow();
|
||||
return a / b;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_divide(A a, A b, const std::integral_constant<int, unchecked>&)
|
||||
{
|
||||
return a / b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_left_shift(A a, unsigned long long shift, const std::integral_constant<int, checked>&)
|
||||
{
|
||||
if (a && shift)
|
||||
{
|
||||
if ((shift > sizeof(A) * CHAR_BIT) || (a >> (sizeof(A) * CHAR_BIT - shift)))
|
||||
BOOST_MP_THROW_EXCEPTION(std::overflow_error("Shift out of range"));
|
||||
}
|
||||
return a << shift;
|
||||
}
|
||||
template <class A>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR A checked_left_shift(A a, unsigned long long shift, const std::integral_constant<int, unchecked>&)
|
||||
{
|
||||
return (shift >= sizeof(A) * CHAR_BIT) ? 0 : a << shift;
|
||||
}
|
||||
|
||||
}}}} // namespace boost::multiprecision::backends::detail
|
||||
|
||||
#endif
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_COMPARISON_HPP
|
||||
#define BOOST_MP_CPP_INT_COMPARISON_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/constexpr.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 <std::size_t MinBits, std::size_t MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
return (a.sign() == b.sign()) && (a.size() == b.size()) && std_constexpr::equal(a.limbs(), a.limbs() + a.size(), b.limbs());
|
||||
}
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
return (a.sign() == b.sign()) && (a.size() == b.size()) && std_constexpr::equal(a.limbs(), a.limbs() + a.size(), b.limbs());
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
return (a.sign() == false) && (a.size() == 1) && (*a.limbs() == b);
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
return (a.sign() == (b < 0)) && (a.size() == 1) && (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b));
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
return (a.size() == 1) && (*a.limbs() == b);
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) 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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
if (a.sign())
|
||||
return true;
|
||||
if (a.size() > 1)
|
||||
return false;
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) 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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
if (a.size() > 1)
|
||||
return false;
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
return (b < 0) ? a.compare(b) < 0 : eval_lt(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
if (a.sign())
|
||||
return false;
|
||||
if (a.size() > 1)
|
||||
return true;
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) 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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) noexcept
|
||||
{
|
||||
if (a.size() > 1)
|
||||
return true;
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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) 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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept
|
||||
{
|
||||
return (a.sign() == b.sign()) && (*a.limbs() == *b.limbs());
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept
|
||||
{
|
||||
return *a.limbs() == *b.limbs();
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::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) noexcept
|
||||
{
|
||||
return !a.sign() && (*a.limbs() == b);
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<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) noexcept
|
||||
{
|
||||
return (a.sign() == (b < 0)) && (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b));
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::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) noexcept
|
||||
{
|
||||
return *a.limbs() == b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<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) noexcept
|
||||
{
|
||||
using ui_type = typename boost::multiprecision::detail::make_unsigned<S>::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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept
|
||||
{
|
||||
if (a.sign() != b.sign())
|
||||
return a.sign();
|
||||
return a.sign() ? *a.limbs() > *b.limbs() : *a.limbs() < *b.limbs();
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept
|
||||
{
|
||||
return *a.limbs() < *b.limbs();
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::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) noexcept
|
||||
{
|
||||
if (a.sign())
|
||||
return true;
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<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) 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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::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) noexcept
|
||||
{
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<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) noexcept
|
||||
{
|
||||
using ui_type = typename boost::multiprecision::detail::make_unsigned<S>::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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept
|
||||
{
|
||||
if (a.sign() != b.sign())
|
||||
return !a.sign();
|
||||
return a.sign() ? *a.limbs() < *b.limbs() : *a.limbs() > *b.limbs();
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept
|
||||
{
|
||||
return *a.limbs() > *b.limbs();
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::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) noexcept
|
||||
{
|
||||
if (a.sign())
|
||||
return false;
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<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) 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 <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::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) noexcept
|
||||
{
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<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) noexcept
|
||||
{
|
||||
using ui_type = typename boost::multiprecision::detail::make_unsigned<S>::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
|
||||
|
||||
}}} // namespace boost::multiprecision::backends
|
||||
|
||||
#endif
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 - 2021 John Maddock.
|
||||
// Copyright 2021 Matt Borland.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_CONFIG_HPP
|
||||
#define BOOST_MP_CPP_INT_CONFIG_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <boost/multiprecision/detail/standalone_config.hpp>
|
||||
#include <boost/multiprecision/detail/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
|
||||
namespace detail {
|
||||
|
||||
//
|
||||
// These traits calculate the largest type in the list
|
||||
// [unsigned] long long, long, int, which has the specified number
|
||||
// of bits. Note that int_t and uint_t 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 <std::size_t Bits>
|
||||
struct int_t
|
||||
{
|
||||
using exact = typename std::conditional<Bits <= sizeof(signed char) * CHAR_BIT, signed char,
|
||||
typename std::conditional<Bits <= sizeof(short) * CHAR_BIT, short,
|
||||
typename std::conditional<Bits <= sizeof(int) * CHAR_BIT, int,
|
||||
typename std::conditional<Bits <= sizeof(long) * CHAR_BIT, long,
|
||||
typename std::conditional<Bits <= sizeof(long long) * CHAR_BIT, long long, void
|
||||
>::type>::type>::type>::type>::type;
|
||||
|
||||
using least = typename std::conditional<Bits-1 <= std::numeric_limits<signed char>::digits, signed char,
|
||||
typename std::conditional<Bits-1 <= std::numeric_limits<short>::digits, short,
|
||||
typename std::conditional<Bits-1 <= std::numeric_limits<int>::digits, int,
|
||||
typename std::conditional<Bits-1 <= std::numeric_limits<long>::digits, long,
|
||||
typename std::conditional<Bits-1 <= std::numeric_limits<long long>::digits, long long, void
|
||||
>::type>::type>::type>::type>::type;
|
||||
|
||||
static_assert(!std::is_same<void, exact>::value && !std::is_same<void, least>::value, "Number of bits does not match any standard data type. \
|
||||
Please file an issue at https://github.com/boostorg/multiprecision/ referencing this error from cpp_int_config.hpp");
|
||||
};
|
||||
|
||||
template <std::size_t Bits>
|
||||
struct uint_t
|
||||
{
|
||||
using exact = typename std::conditional<Bits <= sizeof(unsigned char) * CHAR_BIT, unsigned char,
|
||||
typename std::conditional<Bits <= sizeof(unsigned short) * CHAR_BIT, unsigned short,
|
||||
typename std::conditional<Bits <= sizeof(unsigned int) * CHAR_BIT, unsigned int,
|
||||
typename std::conditional<Bits <= sizeof(unsigned long) * CHAR_BIT, unsigned long,
|
||||
typename std::conditional<Bits <= sizeof(unsigned long long) * CHAR_BIT, unsigned long long, void
|
||||
>::type>::type>::type>::type>::type;
|
||||
|
||||
using least = typename std::conditional<Bits <= std::numeric_limits<unsigned char>::digits, unsigned char,
|
||||
typename std::conditional<Bits <= std::numeric_limits<unsigned short>::digits, unsigned short,
|
||||
typename std::conditional<Bits <= std::numeric_limits<unsigned int>::digits, unsigned int,
|
||||
typename std::conditional<Bits <= std::numeric_limits<unsigned long>::digits, unsigned long,
|
||||
typename std::conditional<Bits <= std::numeric_limits<unsigned long long>::digits, unsigned long long, void
|
||||
>::type>::type>::type>::type>::type;
|
||||
|
||||
static_assert(!std::is_same<void, exact>::value && !std::is_same<void, least>::value, "Number of bits does not match any standard data type. \
|
||||
Please file an issue at https://github.com/boostorg/multiprecision/ referencing this error from cpp_int_config.hpp");
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct largest_signed_type
|
||||
{
|
||||
using type = typename std::conditional<
|
||||
1 + std::numeric_limits<long long>::digits == N,
|
||||
long long,
|
||||
typename std::conditional<
|
||||
1 + std::numeric_limits<long>::digits == N,
|
||||
long,
|
||||
typename std::conditional<
|
||||
1 + std::numeric_limits<int>::digits == N,
|
||||
int,
|
||||
typename int_t<N>::exact>::type>::type>::type;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct largest_unsigned_type
|
||||
{
|
||||
using type = typename std::conditional<
|
||||
std::numeric_limits<unsigned long long>::digits == N,
|
||||
unsigned long long,
|
||||
typename std::conditional<
|
||||
std::numeric_limits<unsigned long>::digits == N,
|
||||
unsigned long,
|
||||
typename std::conditional<
|
||||
std::numeric_limits<unsigned int>::digits == N,
|
||||
unsigned int,
|
||||
typename uint_t<N>::exact>::type>::type>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
|
||||
using limb_type = detail::largest_unsigned_type<64>::type;
|
||||
using signed_limb_type = detail::largest_signed_type<64>::type;
|
||||
using double_limb_type = boost::multiprecision::uint128_type;
|
||||
using signed_double_limb_type = boost::multiprecision::int128_type;
|
||||
constexpr limb_type max_block_10 = 1000000000000000000uLL;
|
||||
constexpr limb_type digits_per_block_10 = 18;
|
||||
|
||||
inline BOOST_MP_CXX14_CONSTEXPR limb_type block_multiplier(std::size_t count)
|
||||
{
|
||||
constexpr 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_MP_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
|
||||
|
||||
#else
|
||||
|
||||
using limb_type = detail::largest_unsigned_type<32>::type;
|
||||
using signed_limb_type = detail::largest_signed_type<32>::type ;
|
||||
using double_limb_type = detail::largest_unsigned_type<64>::type;
|
||||
using signed_double_limb_type = detail::largest_signed_type<64>::type ;
|
||||
constexpr limb_type max_block_10 = 1000000000;
|
||||
constexpr limb_type digits_per_block_10 = 9;
|
||||
|
||||
inline limb_type block_multiplier(std::size_t count)
|
||||
{
|
||||
constexpr limb_type values[digits_per_block_10] = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
||||
BOOST_MP_ASSERT(count < digits_per_block_10);
|
||||
return values[count];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
constexpr std::size_t bits_per_limb = sizeof(limb_type) * CHAR_BIT;
|
||||
|
||||
template <class T>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void minmax(const T& a, const T& b, T& aa, T& bb)
|
||||
{
|
||||
if (a < b)
|
||||
{
|
||||
aa = a;
|
||||
bb = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
aa = b;
|
||||
bb = a;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace multiprecision
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_CONFIG_HPP
|
||||
+661
@@ -0,0 +1,661 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_DIVIDE_HPP
|
||||
#define BOOST_MP_CPP_INT_DIVIDE_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/no_exceptions_support.hpp>
|
||||
#include <boost/multiprecision/detail/assert.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends {
|
||||
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
BOOST_MP_CXX14_CONSTEXPR 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.
|
||||
//
|
||||
std::size_t 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();
|
||||
|
||||
std::size_t 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 = (static_cast<double_limb_type>(px[1]) << CppInt1::limb_bits) | px[0];
|
||||
double_limb_type 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 (std::size_t 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 = 1;
|
||||
if ((prem[r_order] <= py[y_order]) && (r_order > 0))
|
||||
{
|
||||
double_limb_type a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
|
||||
double_limb_type b = py[y_order];
|
||||
double_limb_type v = a / b;
|
||||
if (v <= CppInt1::max_limb_value)
|
||||
{
|
||||
guess = static_cast<limb_type>(v);
|
||||
--r_order;
|
||||
}
|
||||
}
|
||||
else if (r_order == 0)
|
||||
{
|
||||
guess = prem[0] / py[y_order];
|
||||
}
|
||||
else
|
||||
{
|
||||
double_limb_type a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
|
||||
double_limb_type 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);
|
||||
BOOST_MP_ASSERT(b);
|
||||
double_limb_type v = a / b;
|
||||
guess = static_cast<limb_type>(v);
|
||||
}
|
||||
BOOST_MP_ASSERT(guess); // If the guess ever gets to zero we go on forever....
|
||||
//
|
||||
// Update result:
|
||||
//
|
||||
std::size_t 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 (std::size_t 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 (std::size_t 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 = (t.size() != y.size() + shift + 1);
|
||||
typename CppInt1::limb_pointer pt = t.limbs();
|
||||
for (std::size_t i = 0; i < shift; ++i)
|
||||
pt[i] = 0;
|
||||
for (std::size_t 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 (std::size_t 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_MP_ASSERT(r.compare_unsigned(y) < 0); // remainder must be less than the divisor or our code has failed
|
||||
}
|
||||
|
||||
template <class CppInt1, class CppInt2>
|
||||
BOOST_MP_CXX14_CONSTEXPR 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_MP_THROW_EXCEPTION(std::overflow_error("Integer Division by zero."));
|
||||
}
|
||||
//
|
||||
// Find the most significant word of numerator.
|
||||
//
|
||||
std::size_t 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 = (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 = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[r_order - 1];
|
||||
double_limb_type 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_MP_ASSERT(r.compare(y) < 0); // remainder must be less than the divisor or our code has failed
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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();
|
||||
if (b.size() == 1)
|
||||
eval_modulus(result, a, *b.limbs());
|
||||
else
|
||||
{
|
||||
using cpp_int_backend1_type = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>;
|
||||
|
||||
divide_unsigned_helper(static_cast<cpp_int_backend1_type*>(nullptr), a, b, result);
|
||||
}
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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,
|
||||
const limb_type mod)
|
||||
{
|
||||
const std::ptrdiff_t n = static_cast<std::ptrdiff_t>(a.size());
|
||||
|
||||
const double_limb_type two_n_mod =
|
||||
static_cast<double_limb_type>
|
||||
(
|
||||
static_cast<double_limb_type>(1u) + static_cast<limb_type>(static_cast<limb_type>(~static_cast<limb_type>(0u) - mod) % mod)
|
||||
);
|
||||
|
||||
limb_type res = a.limbs()[n - 1] % mod;
|
||||
|
||||
for (std::ptrdiff_t i = n - 2; i >= 0; --i)
|
||||
res = static_cast<limb_type>(static_cast<double_limb_type>(static_cast<double_limb_type>(res * two_n_mod) + a.limbs()[i]) % mod);
|
||||
//
|
||||
// We must not modify result until here in case
|
||||
// result and a are the same object:
|
||||
//
|
||||
result.resize(1, 1);
|
||||
*result.limbs() = res;
|
||||
result.sign(a.sign());
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
{
|
||||
const limb_type t = b < 0 ? static_cast<limb_type>(-b) : static_cast<limb_type>(b);
|
||||
eval_modulus(result, a, t);
|
||||
result.sign(a.sign());
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
{
|
||||
// Single limb modulus is in place:
|
||||
eval_modulus(result, result, b);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
{
|
||||
// Single limb modulus is in place:
|
||||
eval_modulus(result, result, b);
|
||||
}
|
||||
|
||||
//
|
||||
// Over again for trivial cpp_int's:
|
||||
//
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
|
||||
*result.limbs() /= *o.limbs();
|
||||
result.sign(result.sign() != o.sign());
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
|
||||
*result.limbs() /= *o.limbs();
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
|
||||
*result.limbs() %= *o.limbs();
|
||||
result.sign(result.sign());
|
||||
}
|
||||
|
||||
}}} // namespace boost::multiprecision::backends
|
||||
|
||||
#endif
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2015 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
#define BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <boost/multiprecision/detail/endian.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Backend, class Unsigned>
|
||||
void assign_bits(Backend& val, Unsigned bits, std::size_t bit_location, std::size_t chunk_bits, const std::integral_constant<bool, false>& tag)
|
||||
{
|
||||
std::size_t limb = bit_location / (sizeof(limb_type) * CHAR_BIT);
|
||||
std::size_t 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, std::size_t bit_location, std::size_t chunk_bits, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
using local_limb_type = typename Backend::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;
|
||||
if ((bit_location < sizeof(bits) * CHAR_BIT) && (bits >>= bit_location))
|
||||
val.resize(2, 2); // May throw!
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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, std::size_t bits, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
std::size_t limb_count = static_cast<unsigned>(bits / (sizeof(limb_type) * CHAR_BIT));
|
||||
if (bits % (sizeof(limb_type) * CHAR_BIT))
|
||||
++limb_count;
|
||||
constexpr std::size_t 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 <std::size_t MinBits, std::size_t 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 std::integral_constant<bool, true>&)
|
||||
{
|
||||
*newval.limbs() = 0;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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, std::size_t chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
typename number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>::backend_type newval;
|
||||
|
||||
using value_type = typename std::iterator_traits<Iterator>::value_type ;
|
||||
using unsigned_value_type = typename boost::multiprecision::detail::make_unsigned<value_type>::type ;
|
||||
using difference_type = typename std::iterator_traits<Iterator>::difference_type ;
|
||||
using size_type = typename boost::multiprecision::detail::make_unsigned<difference_type>::type ;
|
||||
using tag_type = typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag;
|
||||
|
||||
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<std::size_t>(bit_location), chunk_size, tag_type());
|
||||
++i;
|
||||
bit_location += bit_location_change;
|
||||
}
|
||||
|
||||
newval.normalize();
|
||||
|
||||
val.backend().swap(newval);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline typename std::enable_if< !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, std::size_t 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 <std::size_t MinBits, std::size_t MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline typename std::enable_if<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, std::size_t 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;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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, std::size_t chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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, std::size_t chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
#if BOOST_MP_ENDIAN_LITTLE_BYTE
|
||||
if (((chunk_size % CHAR_BIT) == 0) && !msv_first && (sizeof(*i) * CHAR_BIT == chunk_size))
|
||||
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>
|
||||
std::uintmax_t extract_bits(const Backend& val, std::size_t location, std::size_t count, const std::integral_constant<bool, false>& tag)
|
||||
{
|
||||
std::size_t limb = location / (sizeof(limb_type) * CHAR_BIT);
|
||||
std::size_t shift = location % (sizeof(limb_type) * CHAR_BIT);
|
||||
std::uintmax_t result = 0;
|
||||
std::uintmax_t mask = count == std::numeric_limits<std::uintmax_t>::digits ? ~static_cast<std::uintmax_t>(0) : (static_cast<std::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 std::uintmax_t extract_bits(const Backend& val, std::size_t location, std::size_t count, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
typename Backend::local_limb_type result = *val.limbs();
|
||||
typename Backend::local_limb_type mask = count >= std::numeric_limits<typename Backend::local_limb_type>::digits ? ~static_cast<typename Backend::local_limb_type>(0) : (static_cast<typename Backend::local_limb_type>(1u) << count) - 1;
|
||||
return (result >> location) & mask;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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, std::size_t chunk_size, bool msv_first = true)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#endif
|
||||
using tag_type = typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag;
|
||||
if (!val)
|
||||
{
|
||||
*out = 0;
|
||||
++out;
|
||||
return out;
|
||||
}
|
||||
std::size_t bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1;
|
||||
|
||||
std::ptrdiff_t bit_location = msv_first ? static_cast<std::ptrdiff_t>(bitcount - chunk_size) : 0;
|
||||
const std::ptrdiff_t bit_step = msv_first ? static_cast<std::ptrdiff_t>(-static_cast<std::ptrdiff_t>(chunk_size)) : static_cast<std::ptrdiff_t>(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 < static_cast<int>(bitcount)));
|
||||
|
||||
return out;
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace boost::multiprecision
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2020 Madhur Chauhan.
|
||||
// Copyright 2020 John Maddock.
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_MP_INTEL_INTRINSICS_HPP
|
||||
#define BOOST_MP_INTEL_INTRINSICS_HPP
|
||||
//
|
||||
// Select which actual implementation header to use:
|
||||
//
|
||||
#ifdef __has_include
|
||||
#if __has_include(<immintrin.h>)
|
||||
#define BOOST_MP_HAS_IMMINTRIN_H
|
||||
#endif
|
||||
#endif
|
||||
//
|
||||
// If this is GCC/clang, then check that the actual intrinsic exists:
|
||||
//
|
||||
#if defined(__has_builtin) && defined(__GNUC__)
|
||||
#if !__has_builtin(__builtin_ia32_addcarryx_u64) && defined(BOOST_MP_HAS_IMMINTRIN_H) \
|
||||
&& !(defined(BOOST_GCC) && (__GNUC__ >= 9) \
|
||||
&& (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)\
|
||||
|| defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_AMD64) \
|
||||
|| defined(_M_X64) || defined(__amd64__) || defined(_M_X64)))
|
||||
#undef BOOST_MP_HAS_IMMINTRIN_H
|
||||
#endif
|
||||
#elif defined(BOOST_MP_HAS_IMMINTRIN_H) && defined(__GNUC__) && !(defined(BOOST_GCC) && (__GNUC__ >= 9))
|
||||
#undef BOOST_MP_HAS_IMMINTRIN_H
|
||||
#endif
|
||||
|
||||
#if defined(__clang_major__) && (__clang_major__ < 9)
|
||||
// We appear to crash the compiler if we try to use these intrinsics?
|
||||
#undef BOOST_MP_HAS_IMMINTRIN_H
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && (defined(_M_ARM64) || defined(_M_ARM))
|
||||
//
|
||||
// When targeting platforms such as ARM, msvc (and also clang when emulating msvc) still has the
|
||||
// Intel headers in its include path even though they're not usable.
|
||||
// See https://github.com/boostorg/multiprecision/issues/321
|
||||
// Also https://github.com/boostorg/multiprecision/issues/475
|
||||
//
|
||||
#undef BOOST_MP_HAS_IMMINTRIN_H
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE_CC__) && defined(__clang_major__) && (__clang_major__ < 11) && defined(BOOST_MP_HAS_IMMINTRIN_H)
|
||||
// Apple clang has it's own version numbers.
|
||||
#undef BOOST_MP_HAS_IMMINTRIN_H
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// If the compiler supports the intrinsics used by GCC internally
|
||||
// inside <immintrin.h> then we'll use them directly.
|
||||
// This is a bit of defensive programming, mostly for a modern clang
|
||||
// sitting on top of an older GCC header install.
|
||||
//
|
||||
#if defined(__has_builtin) && !defined(BOOST_INTEL)
|
||||
|
||||
# if __has_builtin(__builtin_ia32_addcarryx_u64)
|
||||
# define BOOST_MP_ADDC __builtin_ia32_addcarryx_u
|
||||
# endif
|
||||
|
||||
# if __has_builtin(__builtin_ia32_subborrow_u64)
|
||||
# define BOOST_MP_SUBB __builtin_ia32_subborrow_u
|
||||
# elif __has_builtin(__builtin_ia32_sbb_u64)
|
||||
# define BOOST_MP_SUBB __builtin_ia32_sbb_u
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_MP_ADDC
|
||||
#define BOOST_MP_ADDC _addcarry_u
|
||||
#endif
|
||||
#ifndef BOOST_MP_SUBB
|
||||
#define BOOST_MP_SUBB _subborrow_u
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MP_HAS_IMMINTRIN_H
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
//
|
||||
// This is a subset of the full <immintrin.h> :
|
||||
//
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
|
||||
namespace boost { namespace multiprecision { namespace detail {
|
||||
|
||||
BOOST_MP_FORCEINLINE unsigned char addcarry_limb(unsigned char carry, limb_type a, limb_type b, limb_type* p_result)
|
||||
{
|
||||
#ifdef BOOST_INTEL
|
||||
using cast_type = unsigned __int64;
|
||||
#else
|
||||
using cast_type = unsigned long long;
|
||||
#endif
|
||||
return BOOST_JOIN(BOOST_MP_ADDC, 64)(carry, a, b, reinterpret_cast<cast_type*>(p_result));
|
||||
}
|
||||
|
||||
BOOST_MP_FORCEINLINE unsigned char subborrow_limb(unsigned char carry, limb_type a, limb_type b, limb_type* p_result)
|
||||
{
|
||||
#ifdef BOOST_INTEL
|
||||
using cast_type = unsigned __int64;
|
||||
#else
|
||||
using cast_type = unsigned long long;
|
||||
#endif
|
||||
return BOOST_JOIN(BOOST_MP_SUBB, 64)(carry, a, b, reinterpret_cast<cast_type*>(p_result));
|
||||
}
|
||||
|
||||
}}} // namespace boost::multiprecision::detail
|
||||
|
||||
#else
|
||||
|
||||
namespace boost { namespace multiprecision { namespace detail {
|
||||
|
||||
BOOST_MP_FORCEINLINE unsigned char addcarry_limb(unsigned char carry, limb_type a, limb_type b, limb_type* p_result)
|
||||
{
|
||||
return BOOST_JOIN(BOOST_MP_ADDC, 32)(carry, a, b, reinterpret_cast<unsigned int*>(p_result));
|
||||
}
|
||||
|
||||
BOOST_MP_FORCEINLINE unsigned char subborrow_limb(unsigned char carry, limb_type a, limb_type b, limb_type* p_result)
|
||||
{
|
||||
return BOOST_JOIN(BOOST_MP_SUBB, 32)(carry, a, b, reinterpret_cast<unsigned int*>(p_result));
|
||||
}
|
||||
|
||||
}}} // namespace boost::multiprecision::detail
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_LIMITS_HPP
|
||||
#define BOOST_MP_CPP_INT_LIMITS_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/max_digits10.hpp>
|
||||
|
||||
namespace std {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4307)
|
||||
#endif
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CXX14_CONSTEXPR_IF_DETECTION boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
// Bounded, signed, and no allocator.
|
||||
using result_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> ;
|
||||
using ui_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MaxBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>, ExpressionTemplates>;
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
static
|
||||
#else
|
||||
constexpr
|
||||
#endif
|
||||
const result_type val = -result_type(~ui_type(0));
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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 std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
// Bounded, signed, and an allocator (can't be constexpr).
|
||||
using result_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> ;
|
||||
using ui_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MaxBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>, ExpressionTemplates>;
|
||||
static const result_type val = -result_type(~ui_type(0));
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CXX14_CONSTEXPR_IF_DETECTION boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
// Bounded, unsigned, no allocator (can be constexpr):
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
static
|
||||
#else
|
||||
constexpr
|
||||
#endif
|
||||
const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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 std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
// Bounded and std::size_t with allocator (no constexpr):
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates, bool has_allocator>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const std::integral_constant<bool, false>&, const std::integral_constant<bool, true>&, const std::integral_constant<bool, has_allocator>&)
|
||||
{
|
||||
// Unbounded and signed, never constexpr because there must be an allocator.
|
||||
// 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 <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates, bool has_allocator>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const std::integral_constant<bool, false>&, const std::integral_constant<bool, false>&, const std::integral_constant<bool, has_allocator>&)
|
||||
{
|
||||
// Unbound and unsigned, never constexpr because there must be an allocator.
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CXX14_CONSTEXPR_IF_DETECTION boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
// Bounded and signed, no allocator, can be constexpr.
|
||||
using result_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> ;
|
||||
using ui_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MaxBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>, ExpressionTemplates>;
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
static
|
||||
#else
|
||||
constexpr
|
||||
#endif
|
||||
const result_type val = ~ui_type(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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 std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
// Bounded and signed, has an allocator, never constexpr.
|
||||
using result_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> ;
|
||||
using ui_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MaxBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>, ExpressionTemplates>;
|
||||
static const result_type val = ~ui_type(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CXX14_CONSTEXPR_IF_DETECTION boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&, const std::integral_constant<bool, true>&)
|
||||
{
|
||||
// Bound and unsigned, no allocator so can be constexpr:
|
||||
using result_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> ;
|
||||
using ui_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates>;
|
||||
#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
static
|
||||
#else
|
||||
constexpr
|
||||
#endif
|
||||
const result_type val = ~ui_type(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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 std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&, const std::integral_constant<bool, false>&)
|
||||
{
|
||||
// Bound and unsigned, has an allocator so can never be constexpr:
|
||||
using result_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> ;
|
||||
using ui_type = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates>;
|
||||
static const result_type val = ~ui_type(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates, bool has_allocator>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const std::integral_constant<bool, false>&, const std::integral_constant<bool, true>&, const std::integral_constant<bool, has_allocator>&)
|
||||
{
|
||||
// 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 <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates, bool has_allocator>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const std::integral_constant<bool, false>&, const std::integral_constant<bool, false>&, const std::integral_constant<bool, has_allocator>&)
|
||||
{
|
||||
// Unbound and unsigned:
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <std::size_t MinBits, std::size_t 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> >
|
||||
{
|
||||
using backend_type = boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>;
|
||||
using number_type = boost::multiprecision::number<backend_type, ExpressionTemplates> ;
|
||||
|
||||
public:
|
||||
static constexpr bool is_specialized = true;
|
||||
//
|
||||
// Largest and smallest numbers are bounded only by available memory, set
|
||||
// to zero:
|
||||
//
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type(min)()
|
||||
{
|
||||
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>(), std::integral_constant<bool, std::is_void<Allocator>::value>());
|
||||
}
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type(max)()
|
||||
{
|
||||
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>(), std::integral_constant<bool, std::is_void<Allocator>::value>());
|
||||
}
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type lowest() { return (min)(); }
|
||||
static constexpr int digits = boost::multiprecision::backends::max_precision<backend_type>::value == SIZE_MAX ? INT_MAX : boost::multiprecision::backends::max_precision<backend_type>::value;
|
||||
static constexpr int digits10 = static_cast<int>(boost::multiprecision::detail::calc_digits10_s<static_cast<std::size_t>(digits)>::value);
|
||||
static constexpr int max_digits10 = static_cast<int>(boost::multiprecision::detail::calc_max_digits10_s<static_cast<std::size_t>(digits)>::value);
|
||||
static constexpr bool is_signed = boost::multiprecision::is_signed_number<backend_type>::value;
|
||||
static constexpr bool is_integer = true;
|
||||
static constexpr bool is_exact = true;
|
||||
static constexpr int radix = 2;
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type epsilon() { return 0; }
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type round_error() { return 0; }
|
||||
static constexpr int min_exponent = 0;
|
||||
static constexpr int min_exponent10 = 0;
|
||||
static constexpr int max_exponent = 0;
|
||||
static constexpr int max_exponent10 = 0;
|
||||
static constexpr bool has_infinity = false;
|
||||
static constexpr bool has_quiet_NaN = false;
|
||||
static constexpr bool has_signaling_NaN = false;
|
||||
static constexpr float_denorm_style has_denorm = denorm_absent;
|
||||
static constexpr bool has_denorm_loss = false;
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type infinity() { return 0; }
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type quiet_NaN() { return 0; }
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type signaling_NaN() { return 0; }
|
||||
static BOOST_CXX14_CONSTEXPR_IF_DETECTION number_type denorm_min() { return 0; }
|
||||
static constexpr bool is_iec559 = false;
|
||||
static constexpr bool is_bounded = boost::multiprecision::backends::is_fixed_precision<backend_type>::value;
|
||||
static constexpr bool is_modulo = (boost::multiprecision::backends::is_fixed_precision<backend_type>::value && (Checked == boost::multiprecision::unchecked));
|
||||
static constexpr bool traps = false;
|
||||
static constexpr bool tinyness_before = false;
|
||||
static constexpr float_round_style round_style = round_toward_zero;
|
||||
};
|
||||
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::digits;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::digits10;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_digits10;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_signed;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_integer;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_exact;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::radix;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::min_exponent;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::min_exponent10;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_exponent;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_exponent10;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_infinity;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_quiet_NaN;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_signaling_NaN;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_denorm;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_denorm_loss;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_iec559;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_bounded;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_modulo;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::traps;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::tinyness_before;
|
||||
template <std::size_t MinBits, std::size_t MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::round_style;
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
+295
@@ -0,0 +1,295 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#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>
|
||||
{
|
||||
using type = value_pack<first | value, ARGS...>;
|
||||
};
|
||||
|
||||
template <char NextChar, char... CHARS>
|
||||
struct pack_values
|
||||
{
|
||||
static constexpr std::size_t chars_per_limb = sizeof(limb_type) * CHAR_BIT / 4;
|
||||
static constexpr std::size_t shift = ((sizeof...(CHARS)) % chars_per_limb) * 4;
|
||||
static constexpr limb_type value_to_add = shift ? hex_value<NextChar>::value << shift : hex_value<NextChar>::value;
|
||||
|
||||
using recursive_packed_type = typename pack_values<CHARS...>::type ;
|
||||
using pack_type = typename std::conditional<shift == 0,
|
||||
typename recursive_packed_type::next_type,
|
||||
recursive_packed_type>::type;
|
||||
using type = typename combine_value_to_pack<pack_type, value_to_add>::type;
|
||||
};
|
||||
template <char NextChar>
|
||||
struct pack_values<NextChar>
|
||||
{
|
||||
static constexpr limb_type value_to_add = hex_value<NextChar>::value;
|
||||
|
||||
using type = value_pack<value_to_add>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct strip_leading_zeros_from_pack;
|
||||
template <limb_type... PACK>
|
||||
struct strip_leading_zeros_from_pack<value_pack<PACK...> >
|
||||
{
|
||||
using type = value_pack<PACK...>;
|
||||
};
|
||||
template <limb_type... PACK>
|
||||
struct strip_leading_zeros_from_pack<value_pack<0u, PACK...> >
|
||||
{
|
||||
using type = typename strip_leading_zeros_from_pack<value_pack<PACK...> >::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...> >
|
||||
{
|
||||
using type = value_pack<PACK..., v>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct reverse_value_pack;
|
||||
template <limb_type v, limb_type... VALUES>
|
||||
struct reverse_value_pack<value_pack<v, VALUES...> >
|
||||
{
|
||||
using lead_values = typename reverse_value_pack<value_pack<VALUES...> >::type;
|
||||
using type = typename append_value_to_pack<v, lead_values>::type ;
|
||||
};
|
||||
template <limb_type v>
|
||||
struct reverse_value_pack<value_pack<v> >
|
||||
{
|
||||
using type = value_pack<v>;
|
||||
};
|
||||
template <>
|
||||
struct reverse_value_pack<value_pack<> >
|
||||
{
|
||||
using type = value_pack<>;
|
||||
};
|
||||
|
||||
template <char l1, char l2, char... STR>
|
||||
struct make_packed_value_from_str
|
||||
{
|
||||
static_assert(l1 == '0', "Multi-precision integer literals must be in hexadecimal notation.");
|
||||
static_assert((l2 == 'X') || (l2 == 'x'), "Multi-precision integer literals must be in hexadecimal notation.");
|
||||
using packed_type = typename pack_values<STR...>::type ;
|
||||
using stripped_type = typename strip_leading_zeros_from_pack<packed_type>::type;
|
||||
using type = typename reverse_value_pack<stripped_type>::type ;
|
||||
};
|
||||
|
||||
template <class Pack, class B>
|
||||
struct make_backend_from_pack
|
||||
{
|
||||
static constexpr Pack p = {};
|
||||
static constexpr B value = p;
|
||||
};
|
||||
|
||||
#if !defined(__cpp_inline_variables)
|
||||
template <class Pack, class B>
|
||||
constexpr B make_backend_from_pack<Pack, B>::value;
|
||||
#endif
|
||||
|
||||
template <unsigned Digits>
|
||||
struct signed_cpp_int_literal_result_type
|
||||
{
|
||||
static constexpr unsigned bits = Digits * 4;
|
||||
using backend_type = boost::multiprecision::backends::cpp_int_backend<bits, bits, signed_magnitude, unchecked, void>;
|
||||
using number_type = number<backend_type, et_off> ;
|
||||
};
|
||||
|
||||
template <unsigned Digits>
|
||||
struct unsigned_cpp_int_literal_result_type
|
||||
{
|
||||
static constexpr unsigned bits = Digits * 4;
|
||||
using backend_type = boost::multiprecision::backends::cpp_int_backend<bits, bits, unsigned_magnitude, unchecked, void>;
|
||||
using number_type = number<backend_type, et_off> ;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <char... STR>
|
||||
constexpr typename boost::multiprecision::literals::detail::signed_cpp_int_literal_result_type<static_cast<unsigned>((sizeof...(STR)) - 2u)>::number_type operator"" _cppi()
|
||||
{
|
||||
using pt = typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type;
|
||||
return boost::multiprecision::literals::detail::make_backend_from_pack<pt, typename boost::multiprecision::literals::detail::signed_cpp_int_literal_result_type<static_cast<unsigned>((sizeof...(STR)) - 2u)>::backend_type>::value;
|
||||
}
|
||||
|
||||
template <char... STR>
|
||||
constexpr typename boost::multiprecision::literals::detail::unsigned_cpp_int_literal_result_type<static_cast<unsigned>((sizeof...(STR)) - 2u)>::number_type operator"" _cppui()
|
||||
{
|
||||
using pt = typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type;
|
||||
return boost::multiprecision::literals::detail::make_backend_from_pack<pt, typename boost::multiprecision::literals::detail::unsigned_cpp_int_literal_result_type<static_cast<unsigned>((sizeof...(STR)) - 2u)>::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)() \
|
||||
{ \
|
||||
using pt = typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type; \
|
||||
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)() \
|
||||
{ \
|
||||
using pt = typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type; \
|
||||
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)
|
||||
|
||||
} // namespace literals
|
||||
|
||||
//
|
||||
// Overload unary minus operator for constexpr use:
|
||||
//
|
||||
template <std::size_t 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 <std::size_t 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());
|
||||
}
|
||||
|
||||
}} // namespace boost::multiprecision
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_CORE_HPP
|
||||
+1454
File diff suppressed because it is too large
Load Diff
+848
@@ -0,0 +1,848 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012-20 John Maddock.
|
||||
// Copyright 2019-20 Christopher Kormanyos.
|
||||
// Copyright 2019-20 Madhur Chauhan.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_MULTIPLY_HPP
|
||||
#define BOOST_MP_CPP_INT_MULTIPLY_HPP
|
||||
|
||||
#include <limits>
|
||||
#include <boost/multiprecision/detail/standalone_config.hpp>
|
||||
#include <boost/multiprecision/detail/endian.hpp>
|
||||
#include <boost/multiprecision/detail/assert.hpp>
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends {
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
//
|
||||
// Multiplication by a single limb:
|
||||
//
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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) noexcept((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)
|
||||
{
|
||||
std::size_t i = result.size();
|
||||
result.resize(i + 1, i + 1);
|
||||
if (result.size() > i)
|
||||
result.limbs()[i] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.sign(a.sign());
|
||||
if (is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, std::size_t /*required*/) {}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, class Allocator1>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, Allocator1>& result, std::size_t required)
|
||||
{
|
||||
if (result.size() < required)
|
||||
result.resize(required, required);
|
||||
}
|
||||
//
|
||||
// Minimum number of limbs required for Karatsuba to be worthwhile:
|
||||
//
|
||||
#ifdef BOOST_MP_KARATSUBA_CUTOFF
|
||||
const size_t karatsuba_cutoff = BOOST_MP_KARATSUBA_CUTOFF;
|
||||
#else
|
||||
const size_t karatsuba_cutoff = 40;
|
||||
#endif
|
||||
//
|
||||
// Core (recursive) Karatsuba multiplication, all the storage required is allocated upfront and
|
||||
// passed down the stack in this routine. Note that all the cpp_int_backend's must be the same type
|
||||
// and full variable precision. Karatsuba really doesn't play nice with fixed-size integers. If necessary
|
||||
// fixed precision integers will get aliased as variable-precision types before this is called.
|
||||
//
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
inline void multiply_karatsuba(
|
||||
cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& result,
|
||||
const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a,
|
||||
const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& b,
|
||||
typename cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>::scoped_shared_storage& storage)
|
||||
{
|
||||
using cpp_int_type = cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>;
|
||||
|
||||
std::size_t as = a.size();
|
||||
std::size_t bs = b.size();
|
||||
//
|
||||
// Termination condition: if either argument is smaller than karatsuba_cutoff
|
||||
// then schoolboy multiplication will be faster:
|
||||
//
|
||||
if ((as < karatsuba_cutoff) || (bs < karatsuba_cutoff))
|
||||
{
|
||||
eval_multiply(result, a, b);
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Partitioning size: split the larger of a and b into 2 halves
|
||||
//
|
||||
std::size_t n = (as > bs ? as : bs) / 2 + 1;
|
||||
//
|
||||
// Partition a and b into high and low parts.
|
||||
// ie write a, b as a = a_h * 2^n + a_l, b = b_h * 2^n + b_l
|
||||
//
|
||||
// We could copy the high and low parts into new variables, but we'll
|
||||
// use aliasing to reference the internal limbs of a and b. There is one wart here:
|
||||
// if a and b are mismatched in size, then n may be larger than the smaller
|
||||
// of a and b. In that situation the high part is zero, and we have no limbs
|
||||
// to alias, so instead alias a local variable.
|
||||
// This raises 2 questions:
|
||||
// * Is this the best way to partition a and b?
|
||||
// * Since we have one high part zero, the arithmetic simplifies considerably,
|
||||
// so should we have a special routine for this?
|
||||
//
|
||||
std::size_t sz = (std::min)(as, n);
|
||||
const cpp_int_type a_l(a.limbs(), 0, sz);
|
||||
|
||||
sz = (std::min)(bs, n);
|
||||
const cpp_int_type b_l(b.limbs(), 0, sz);
|
||||
|
||||
limb_type zero = 0;
|
||||
const cpp_int_type a_h(as > n ? a.limbs() + n : &zero, 0, as > n ? as - n : 1);
|
||||
const cpp_int_type b_h(bs > n ? b.limbs() + n : &zero, 0, bs > n ? bs - n : 1);
|
||||
//
|
||||
// The basis for the Karatsuba algorithm is as follows:
|
||||
//
|
||||
// let x = a_h * b_ h
|
||||
// y = a_l * b_l
|
||||
// z = (a_h + a_l)*(b_h + b_l) - x - y
|
||||
// and therefore a * b = x * (2 ^ (2 * n))+ z * (2 ^ n) + y
|
||||
//
|
||||
// Begin by allocating our temporaries, these alias the memory already allocated in the shared storage:
|
||||
//
|
||||
cpp_int_type t1(storage, 2 * n + 2);
|
||||
cpp_int_type t2(storage, n + 1);
|
||||
cpp_int_type t3(storage, n + 1);
|
||||
//
|
||||
// Now we want:
|
||||
//
|
||||
// result = | a_h*b_h | a_l*b_l |
|
||||
// (bits) <-- 2*n -->
|
||||
//
|
||||
// We create aliases for the low and high parts of result, and multiply directly into them:
|
||||
//
|
||||
cpp_int_type result_low(result.limbs(), 0, 2 * n);
|
||||
cpp_int_type result_high(result.limbs(), 2 * n, result.size() - 2 * n);
|
||||
//
|
||||
// low part of result is a_l * b_l:
|
||||
//
|
||||
multiply_karatsuba(result_low, a_l, b_l, storage);
|
||||
//
|
||||
// We haven't zeroed out memory in result, so set to zero any unused limbs,
|
||||
// if a_l and b_l have mostly random bits then nothing happens here, but if
|
||||
// one is zero or nearly so, then a memset might be faster... it's not clear
|
||||
// that it's worth the extra logic though (and is darn hard to measure
|
||||
// what the "average" case is).
|
||||
//
|
||||
for (std::size_t i = result_low.size(); i < 2 * n; ++i)
|
||||
result.limbs()[i] = 0;
|
||||
//
|
||||
// Set the high part of result to a_h * b_h:
|
||||
//
|
||||
multiply_karatsuba(result_high, a_h, b_h, storage);
|
||||
for (std::size_t i = result_high.size() + 2 * n; i < result.size(); ++i)
|
||||
result.limbs()[i] = 0;
|
||||
//
|
||||
// Now calculate (a_h+a_l)*(b_h+b_l):
|
||||
//
|
||||
add_unsigned(t2, a_l, a_h);
|
||||
add_unsigned(t3, b_l, b_h);
|
||||
multiply_karatsuba(t1, t2, t3, storage); // t1 = (a_h+a_l)*(b_h+b_l)
|
||||
//
|
||||
// There is now a slight deviation from Karatsuba, we want to subtract
|
||||
// a_l*b_l + a_h*b_h from t1, but rather than use an addition and a subtraction
|
||||
// plus one temporary, we'll use 2 subtractions. On the minus side, a subtraction
|
||||
// is on average slightly slower than an addition, but we save a temporary (ie memory)
|
||||
// and also hammer the same piece of memory over and over rather than 2 disparate
|
||||
// memory regions. Overall it seems to be a slight win.
|
||||
//
|
||||
subtract_unsigned(t1, t1, result_high);
|
||||
subtract_unsigned(t1, t1, result_low);
|
||||
//
|
||||
// The final step is to left shift t1 by n bits and add to the result.
|
||||
// Rather than do an actual left shift, we can simply alias the result
|
||||
// and add to the alias:
|
||||
//
|
||||
cpp_int_type result_alias(result.limbs(), n, result.size() - n);
|
||||
add_unsigned(result_alias, result_alias, t1);
|
||||
//
|
||||
// Free up storage for use by sister branches to this one:
|
||||
//
|
||||
storage.deallocate(t1.capacity() + t2.capacity() + t3.capacity());
|
||||
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
inline std::size_t karatsuba_storage_size(std::size_t s)
|
||||
{
|
||||
//
|
||||
// This estimates how much memory we will need based on
|
||||
// s-limb multiplication. In an ideal world the number of limbs
|
||||
// would halve with each recursion, and our storage requirements
|
||||
// would be 4s in the limit, and rather less in practice since
|
||||
// we bail out long before we reach one limb. In the real world
|
||||
// we don't quite halve s in each recursion, so this is an heuristic
|
||||
// which over-estimates how much we need. We could compute an exact
|
||||
// value, but it would be rather time consuming.
|
||||
//
|
||||
return 5 * s;
|
||||
}
|
||||
//
|
||||
// There are 2 entry point routines for Karatsuba multiplication:
|
||||
// one for variable precision types, and one for fixed precision types.
|
||||
// These are responsible for allocating all the storage required for the recursive
|
||||
// routines above, and are always at the outermost level.
|
||||
//
|
||||
// Normal variable precision case comes first:
|
||||
//
|
||||
template <std::size_t MinBits, std::size_t MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
inline typename std::enable_if<!is_fixed_precision<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value>::type
|
||||
setup_karatsuba(
|
||||
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result,
|
||||
const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& a,
|
||||
const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& b)
|
||||
{
|
||||
std::size_t as = a.size();
|
||||
std::size_t bs = b.size();
|
||||
std::size_t s = as > bs ? as : bs;
|
||||
std::size_t storage_size = karatsuba_storage_size(s);
|
||||
if (storage_size < 300)
|
||||
{
|
||||
//
|
||||
// Special case: if we don't need too much memory, we can use stack based storage
|
||||
// and save a call to the allocator, this allows us to use Karatsuba multiply
|
||||
// at lower limb counts than would otherwise be possible:
|
||||
//
|
||||
limb_type limbs[300];
|
||||
typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::scoped_shared_storage storage(limbs, storage_size);
|
||||
multiply_karatsuba(result, a, b, storage);
|
||||
}
|
||||
else
|
||||
{
|
||||
typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::scoped_shared_storage storage(result.allocator(), storage_size);
|
||||
multiply_karatsuba(result, a, b, storage);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline typename std::enable_if<is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_fixed_precision<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value || is_fixed_precision<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
|
||||
setup_karatsuba(
|
||||
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)
|
||||
{
|
||||
//
|
||||
// Now comes the fixed precision case.
|
||||
// In fact Karatsuba doesn't really work with fixed precision since the logic
|
||||
// requires that we calculate all the bits of the result (especially in the
|
||||
// temporaries used internally). So... we'll convert all the arguments
|
||||
// to variable precision types by aliasing them, this also
|
||||
// reduce the number of template instantations:
|
||||
//
|
||||
using variable_precision_type = cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> >;
|
||||
variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
|
||||
std::size_t as = a.size();
|
||||
std::size_t bs = b.size();
|
||||
std::size_t s = as > bs ? as : bs;
|
||||
std::size_t sz = as + bs;
|
||||
std::size_t storage_size = karatsuba_storage_size(s);
|
||||
|
||||
if (!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || (sz * sizeof(limb_type) * CHAR_BIT <= MaxBits1))
|
||||
{
|
||||
// Result is large enough for all the bits of the result, so we can use aliasing:
|
||||
result.resize(sz, sz);
|
||||
variable_precision_type t(result.limbs(), 0, result.size());
|
||||
typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
|
||||
multiply_karatsuba(t, a_t, b_t, storage);
|
||||
result.resize(t.size(), t.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Not enough bit in result for the answer, so we must use a temporary
|
||||
// and then truncate (ie modular arithmetic):
|
||||
//
|
||||
typename variable_precision_type::scoped_shared_storage storage(variable_precision_type::allocator_type(), sz + storage_size);
|
||||
variable_precision_type t(storage, sz);
|
||||
multiply_karatsuba(t, a_t, b_t, storage);
|
||||
//
|
||||
// If there is truncation, and result is a checked type then this will throw:
|
||||
//
|
||||
result = t;
|
||||
}
|
||||
}
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline typename std::enable_if<!is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_fixed_precision<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_fixed_precision<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
|
||||
setup_karatsuba(
|
||||
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)
|
||||
{
|
||||
//
|
||||
// Variable precision, mixed arguments, just alias and forward:
|
||||
//
|
||||
using variable_precision_type = cpp_int_backend<0, 0, signed_magnitude, unchecked, std::allocator<limb_type> >;
|
||||
variable_precision_type a_t(a.limbs(), 0, a.size()), b_t(b.limbs(), 0, b.size());
|
||||
std::size_t as = a.size();
|
||||
std::size_t bs = b.size();
|
||||
std::size_t s = as > bs ? as : bs;
|
||||
std::size_t sz = as + bs;
|
||||
std::size_t storage_size = karatsuba_storage_size(s);
|
||||
|
||||
result.resize(sz, sz);
|
||||
variable_precision_type t(result.limbs(), 0, result.size());
|
||||
typename variable_precision_type::scoped_shared_storage storage(t.allocator(), storage_size);
|
||||
multiply_karatsuba(t, a_t, b_t, storage);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR void
|
||||
eval_multiply_comba(
|
||||
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) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
//
|
||||
// see PR #182
|
||||
// Comba Multiplier - based on Paul Comba's
|
||||
// Exponentiation cryptosystems on the IBM PC, 1990
|
||||
//
|
||||
std::ptrdiff_t as = a.size(),
|
||||
bs = b.size(),
|
||||
rs = result.size();
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
|
||||
|
||||
double_limb_type carry = 0,
|
||||
temp = 0;
|
||||
limb_type overflow = 0;
|
||||
const std::size_t limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
const bool must_throw = rs < as + bs - 1;
|
||||
for (std::ptrdiff_t r = 0, lim = (std::min)(rs, as + bs - 1); r < lim; ++r, overflow = 0)
|
||||
{
|
||||
std::ptrdiff_t i = r >= as ? as - 1 : r,
|
||||
j = r - i,
|
||||
k = i < bs - j ? i + 1 : bs - j; // min(i+1, bs-j);
|
||||
|
||||
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs() + i;
|
||||
typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs() + j;
|
||||
|
||||
temp = carry;
|
||||
carry += static_cast<double_limb_type>(*(pa)) * (*(pb));
|
||||
overflow += carry < temp;
|
||||
for (--k; k; k--)
|
||||
{
|
||||
temp = carry;
|
||||
carry += static_cast<double_limb_type>(*(--pa)) * (*(++pb));
|
||||
overflow += carry < temp;
|
||||
}
|
||||
*(pr++) = static_cast<limb_type>(carry);
|
||||
carry = (static_cast<double_limb_type>(overflow) << limb_bits) | (carry >> limb_bits);
|
||||
}
|
||||
if (carry || must_throw)
|
||||
{
|
||||
resize_for_carry(result, as + bs);
|
||||
if (static_cast<int>(result.size()) >= as + bs)
|
||||
*pr = static_cast<limb_type>(carry);
|
||||
}
|
||||
}
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (karatsuba_cutoff * sizeof(limb_type) * CHAR_BIT > MaxBits1)
|
||||
&& (karatsuba_cutoff * sizeof(limb_type)* CHAR_BIT > MaxBits2)
|
||||
&& (karatsuba_cutoff * sizeof(limb_type)* CHAR_BIT > MaxBits3)))
|
||||
{
|
||||
// Uses simple (O(n^2)) multiplication when the limbs are less
|
||||
// otherwise switches to karatsuba algorithm based on experimental value (~40 limbs)
|
||||
//
|
||||
// Trivial cases first:
|
||||
//
|
||||
std::size_t as = a.size();
|
||||
std::size_t 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;
|
||||
}
|
||||
|
||||
constexpr double_limb_type limb_max = static_cast<double_limb_type>(~static_cast<limb_type>(0u));
|
||||
constexpr double_limb_type double_limb_max = static_cast<double_limb_type>(~static_cast<double_limb_type>(0u));
|
||||
|
||||
result.resize(as + bs, as + bs - 1);
|
||||
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if (!BOOST_MP_IS_CONST_EVALUATED(as) && (as >= karatsuba_cutoff && bs >= karatsuba_cutoff))
|
||||
#else
|
||||
if (as >= karatsuba_cutoff && bs >= karatsuba_cutoff)
|
||||
#endif
|
||||
{
|
||||
setup_karatsuba(result, a, b);
|
||||
//
|
||||
// Set the sign of the result:
|
||||
//
|
||||
result.sign(a.sign() != b.sign());
|
||||
return;
|
||||
}
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
|
||||
static_assert(double_limb_max - 2 * limb_max >= limb_max * limb_max, "failed limb size sanity check");
|
||||
|
||||
#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(as))
|
||||
{
|
||||
for (std::size_t i = 0; i < result.size(); ++i)
|
||||
pr[i] = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
std::memset(pr, 0, result.size() * sizeof(limb_type));
|
||||
|
||||
#if defined(BOOST_MP_COMBA)
|
||||
//
|
||||
// Comba Multiplier might not be efficient because of less efficient assembly
|
||||
// by the compiler as of 09/01/2020 (DD/MM/YY). See PR #182
|
||||
// Till then this will lay dormant :(
|
||||
//
|
||||
eval_multiply_comba(result, a, b);
|
||||
#else
|
||||
|
||||
double_limb_type carry = 0;
|
||||
for (std::size_t i = 0; i < as; ++i)
|
||||
{
|
||||
BOOST_MP_ASSERT(result.size() > i);
|
||||
std::size_t inner_limit = !is_fixed_precision<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value ? bs : (std::min)(result.size() - i, bs);
|
||||
std::size_t j = 0;
|
||||
for (; j < inner_limit; ++j)
|
||||
{
|
||||
BOOST_MP_ASSERT(i + j < result.size());
|
||||
#if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
|
||||
BOOST_MP_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_MP_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_MP_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
|
||||
}
|
||||
if (carry)
|
||||
{
|
||||
resize_for_carry(result, i + j + 1); // May throw if checking is enabled
|
||||
if (i + j < result.size())
|
||||
#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 = 0;
|
||||
}
|
||||
#endif // ifdef(BOOST_MP_COMBA) ends
|
||||
|
||||
result.normalize();
|
||||
//
|
||||
// Set the sign of the result:
|
||||
//
|
||||
result.sign(a.sign() != b.sign());
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>()))))
|
||||
{
|
||||
eval_multiply(result, result, a);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const limb_type&>()))))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept(
|
||||
(noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const limb_type&>())))
|
||||
&& (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>())))
|
||||
)
|
||||
{
|
||||
if (val <= (std::numeric_limits<limb_type>::max)())
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
#if BOOST_MP_ENDIAN_LITTLE_BYTE && !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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const double_limb_type&>()))))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const limb_type&>()))))
|
||||
{
|
||||
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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept((noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const limb_type&>()))))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept(
|
||||
(noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const limb_type&>())))
|
||||
&& (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>())))
|
||||
)
|
||||
{
|
||||
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 BOOST_MP_ENDIAN_LITTLE_BYTE && !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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!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)
|
||||
noexcept(
|
||||
(noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const limb_type&>())))
|
||||
&& (noexcept(eval_multiply(std::declval<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>(), std::declval<const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&>())))
|
||||
)
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
//
|
||||
// Now over again for trivial cpp_int's:
|
||||
//
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
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) noexcept((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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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)
|
||||
{
|
||||
constexpr signed_double_limb_type mask = static_cast<signed_double_limb_type>(~static_cast<limb_type>(0));
|
||||
constexpr std::size_t limb_bits = static_cast<std::size_t>(sizeof(limb_type) * CHAR_BIT);
|
||||
|
||||
bool s = false;
|
||||
if (a < 0)
|
||||
{
|
||||
a = -a;
|
||||
s = true;
|
||||
}
|
||||
if (b < 0)
|
||||
{
|
||||
b = -b;
|
||||
s = !s;
|
||||
}
|
||||
double_limb_type w = a & mask;
|
||||
double_limb_type x = static_cast<double_limb_type>(a >> limb_bits);
|
||||
double_limb_type y = b & mask;
|
||||
double_limb_type z = static_cast<double_limb_type>(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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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)
|
||||
{
|
||||
constexpr signed_double_limb_type mask = static_cast<signed_double_limb_type>(~static_cast<limb_type>(0));
|
||||
constexpr std::size_t limb_bits = static_cast<std::size_t>(sizeof(limb_type) * CHAR_BIT);
|
||||
|
||||
double_limb_type w = a & mask;
|
||||
double_limb_type x = a >> limb_bits;
|
||||
double_limb_type y = b & mask;
|
||||
double_limb_type 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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
|
||||
std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
|
||||
!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)
|
||||
{
|
||||
using canonical_type = 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;
|
||||
eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
|
||||
result.sign(a.sign() != b.sign());
|
||||
}
|
||||
|
||||
template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_signed<SI>::value && boost::multiprecision::detail::is_integral<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 <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
|
||||
BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::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 BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::multiprecision::backends
|
||||
|
||||
#endif
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_SERIALIZE_HPP
|
||||
#define BOOST_MP_CPP_INT_SERIALIZE_HPP
|
||||
|
||||
#ifndef BOOST_MP_STANDALONE
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace archive {
|
||||
|
||||
class binary_oarchive;
|
||||
class binary_iarchive;
|
||||
|
||||
} // namespace archive
|
||||
|
||||
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 std::integral_constant<bool, false>
|
||||
{};
|
||||
template <>
|
||||
struct is_binary_archive<boost::archive::binary_oarchive> : public std::integral_constant<bool, true>
|
||||
{};
|
||||
template <>
|
||||
struct is_binary_archive<boost::archive::binary_iarchive> : public std::integral_constant<bool, 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, std::integral_constant<bool, false> const&, std::integral_constant<bool, false> const&, std::integral_constant<bool, false> const&)
|
||||
{
|
||||
// Load.
|
||||
// Non-trivial.
|
||||
// Non binary.
|
||||
|
||||
using boost::make_nvp;
|
||||
bool s;
|
||||
ar& make_nvp("sign", s);
|
||||
std::size_t limb_count;
|
||||
std::size_t byte_count;
|
||||
ar& make_nvp("byte-count", 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& make_nvp("byte", 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, std::integral_constant<bool, true> const&, std::integral_constant<bool, false> const&, std::integral_constant<bool, false> const&)
|
||||
{
|
||||
// Store.
|
||||
// Non-trivial.
|
||||
// Non binary.
|
||||
|
||||
using boost::make_nvp;
|
||||
bool s = val.sign();
|
||||
ar& make_nvp("sign", s);
|
||||
limb_type* pl = val.limbs();
|
||||
std::size_t limb_count = val.size();
|
||||
std::size_t byte_count = limb_count * sizeof(limb_type);
|
||||
ar& make_nvp("byte-count", 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& make_nvp("byte", byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, std::integral_constant<bool, false> const&, std::integral_constant<bool, true> const&, std::integral_constant<bool, false> const&)
|
||||
{
|
||||
// Load.
|
||||
// Trivial.
|
||||
// Non binary.
|
||||
using boost::make_nvp;
|
||||
bool s;
|
||||
typename Int::local_limb_type l = 0;
|
||||
ar& make_nvp("sign", s);
|
||||
std::size_t byte_count;
|
||||
ar& make_nvp("byte-count", byte_count);
|
||||
for (std::size_t i = 0; i < byte_count; ++i)
|
||||
{
|
||||
unsigned char b;
|
||||
ar& make_nvp("byte", 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, std::integral_constant<bool, true> const&, std::integral_constant<bool, true> const&, std::integral_constant<bool, false> const&)
|
||||
{
|
||||
// Store.
|
||||
// Trivial.
|
||||
// Non binary.
|
||||
using boost::make_nvp;
|
||||
bool s = val.sign();
|
||||
typename Int::local_limb_type l = *val.limbs();
|
||||
ar& make_nvp("sign", s);
|
||||
std::size_t limb_count = sizeof(l);
|
||||
ar& make_nvp("byte-count", 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& make_nvp("byte", b);
|
||||
}
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, std::integral_constant<bool, false> const&, std::integral_constant<bool, false> const&, std::integral_constant<bool, 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, std::integral_constant<bool, true> const&, std::integral_constant<bool, false> const&, std::integral_constant<bool, 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, std::integral_constant<bool, false> const&, std::integral_constant<bool, true> const&, std::integral_constant<bool, 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, std::integral_constant<bool, true> const&, std::integral_constant<bool, true> const&, std::integral_constant<bool, true> const&)
|
||||
{
|
||||
// Store.
|
||||
// Trivial.
|
||||
// Binary.
|
||||
bool s = val.sign();
|
||||
ar& s;
|
||||
ar.save_binary(val.limbs(), sizeof(*val.limbs()));
|
||||
}
|
||||
|
||||
} // namespace cpp_int_detail
|
||||
|
||||
template <class Archive, std::size_t MinBits, std::size_t 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*/)
|
||||
{
|
||||
using archive_save_tag = typename Archive::is_saving ;
|
||||
using save_tag = std::integral_constant<bool, archive_save_tag::value> ;
|
||||
using trivial_tag = std::integral_constant<bool, mp::backends::is_trivial_cpp_int<mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value>;
|
||||
using binary_tag = typename cpp_int_detail::is_binary_archive<Archive>::type ;
|
||||
|
||||
// Just dispatch to the correct method:
|
||||
cpp_int_detail::do_serialize(ar, val, save_tag(), trivial_tag(), binary_tag());
|
||||
}
|
||||
|
||||
} // namespace serialization
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MP_STANDALONE
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_SERIALIZE_HPP
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#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() {}
|
||||
|
||||
using next_type = value_pack<0, VALUES...>;
|
||||
};
|
||||
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();
|
||||
}
|
||||
|
||||
}}}} // namespace boost::multiprecision::literals::detail
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_CORE_HPP
|
||||
Reference in New Issue
Block a user