Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+368
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
File diff suppressed because it is too large Load Diff
+848
View File
@@ -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
View File
@@ -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
View File
@@ -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