/usr/include/boost/multiprecision
Edit: /usr/include/boost/multiprecision/gmp.hpp (113421B)
///////////////////////////////////////////////////////////////////////////////
// Copyright 2011 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_ER_GMP_BACKEND_HPP
#define BOOST_MATH_ER_GMP_BACKEND_HPP
#include
#include
#include
#include
#include
#include
#include
#include
#include
//
// Some includes we need from Boost.Math, since we rely on that library to provide these functions:
//
#include
#include
#include
#include
#include
#include
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
#include
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#if defined(__MPIR_VERSION) && defined(__MPIR_VERSION_MINOR) && defined(__MPIR_VERSION_PATCHLEVEL)
#define BOOST_MP_MPIR_VERSION (__MPIR_VERSION * 10000 + __MPIR_VERSION_MINOR * 100 + __MPIR_VERSION_PATCHLEVEL)
#else
#define BOOST_MP_MPIR_VERSION 0
#endif
#include
#include
#include
#include
namespace boost {
namespace multiprecision {
namespace backends {
#ifdef BOOST_MSVC
// warning C4127: conditional expression is constant
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
template
struct gmp_float;
struct gmp_int;
struct gmp_rational;
} // namespace backends
template <>
struct number_category : public mpl::int_
{};
template <>
struct number_category : public mpl::int_
{};
template
struct number_category > : public mpl::int_
{};
namespace backends {
//
// Within this file, the only functions we mark as noexcept are those that manipulate
// (but don't create) an mpf_t. All other types may allocate at pretty much any time
// via a user-supplied allocator, and therefore throw.
//
namespace detail {
template
struct gmp_float_imp
{
#ifdef BOOST_HAS_LONG_LONG
typedef mpl::list signed_types;
typedef mpl::list unsigned_types;
#else
typedef mpl::list signed_types;
typedef mpl::list unsigned_types;
#endif
typedef mpl::list float_types;
typedef long exponent_type;
gmp_float_imp() BOOST_NOEXCEPT
{
m_data[0]._mp_d = 0; // uninitialized m_data
}
gmp_float_imp(const gmp_float_imp& o)
{
//
// We have to do an init followed by a set here, otherwise *this may be at
// a lower precision than o: seems like mpf_init_set copies just enough bits
// to get the right value, but if it's then used in further calculations
// things go badly wrong!!
//
mpf_init2(m_data, mpf_get_prec(o.data()));
if (o.m_data[0]._mp_d)
mpf_set(m_data, o.m_data);
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_float_imp(gmp_float_imp&& o) BOOST_NOEXCEPT
{
m_data[0] = o.m_data[0];
o.m_data[0]._mp_d = 0;
}
#endif
gmp_float_imp& operator=(const gmp_float_imp& o)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, mpf_get_prec(o.data()));
if (mpf_get_prec(data()) != mpf_get_prec(o.data()))
{
mpf_t t;
mpf_init2(t, mpf_get_prec(o.data()));
mpf_set(t, o.data());
mpf_swap(data(), t);
mpf_clear(t);
}
else
{
if (o.m_data[0]._mp_d)
mpf_set(m_data, o.m_data);
}
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_float_imp& operator=(gmp_float_imp&& o) BOOST_NOEXCEPT
{
mpf_swap(m_data, o.m_data);
return *this;
}
#endif
#ifdef BOOST_HAS_LONG_LONG
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
gmp_float_imp& operator=(boost::ulong_long_type i)
{
*this = static_cast(i);
return *this;
}
#else
gmp_float_imp& operator=(boost::ulong_long_type i)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
boost::ulong_long_type mask = ((((1uLL << (std::numeric_limits::digits - 1)) - 1) << 1) | 1uLL);
unsigned shift = 0;
mpf_t t;
mpf_init2(t, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
mpf_set_ui(m_data, 0);
while (i)
{
mpf_set_ui(t, static_cast(i & mask));
if (shift)
mpf_mul_2exp(t, t, shift);
mpf_add(m_data, m_data, t);
shift += std::numeric_limits::digits;
i >>= std::numeric_limits::digits;
}
mpf_clear(t);
return *this;
}
#endif
gmp_float_imp& operator=(boost::long_long_type i)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
bool neg = i < 0;
*this = static_cast(boost::multiprecision::detail::unsigned_abs(i));
if (neg)
mpf_neg(m_data, m_data);
return *this;
}
#endif
gmp_float_imp& operator=(unsigned long i)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
mpf_set_ui(m_data, i);
return *this;
}
gmp_float_imp& operator=(long i)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
mpf_set_si(m_data, i);
return *this;
}
gmp_float_imp& operator=(double d)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
mpf_set_d(m_data, d);
return *this;
}
gmp_float_imp& operator=(long double a)
{
using std::floor;
using std::frexp;
using std::ldexp;
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
if (a == 0)
{
mpf_set_si(m_data, 0);
return *this;
}
if (a == 1)
{
mpf_set_si(m_data, 1);
return *this;
}
BOOST_ASSERT(!(boost::math::isinf)(a));
BOOST_ASSERT(!(boost::math::isnan)(a));
int e;
long double f, term;
mpf_set_ui(m_data, 0u);
f = frexp(a, &e);
static const int shift = std::numeric_limits::digits - 1;
while (f)
{
// extract int sized bits from f:
f = ldexp(f, shift);
term = floor(f);
e -= shift;
mpf_mul_2exp(m_data, m_data, shift);
if (term > 0)
mpf_add_ui(m_data, m_data, static_cast(term));
else
mpf_sub_ui(m_data, m_data, static_cast(-term));
f -= term;
}
if (e > 0)
mpf_mul_2exp(m_data, m_data, e);
else if (e < 0)
mpf_div_2exp(m_data, m_data, -e);
return *this;
}
gmp_float_imp& operator=(const char* s)
{
if (m_data[0]._mp_d == 0)
mpf_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision()));
if (s && (*s == '+'))
++s; // Leading "+" sign not supported by mpf_set_str:
if (0 != mpf_set_str(m_data, s, 10))
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("The string \"") + s + std::string("\"could not be interpreted as a valid floating point number.")));
return *this;
}
void swap(gmp_float_imp& o) BOOST_NOEXCEPT
{
mpf_swap(m_data, o.m_data);
}
std::string str(std::streamsize digits, std::ios_base::fmtflags f) const
{
BOOST_ASSERT(m_data[0]._mp_d);
bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
bool fixed = (f & std::ios_base::fixed) == std::ios_base::fixed;
std::streamsize org_digits(digits);
if (scientific && digits)
++digits;
std::string result;
mp_exp_t e;
void* (*alloc_func_ptr)(size_t);
void* (*realloc_func_ptr)(void*, size_t, size_t);
void (*free_func_ptr)(void*, size_t);
mp_get_memory_functions(&alloc_func_ptr, &realloc_func_ptr, &free_func_ptr);
if (mpf_sgn(m_data) == 0)
{
e = 0;
result = "0";
if (fixed && digits)
++digits;
}
else
{
char* ps = mpf_get_str(0, &e, 10, static_cast(digits), m_data);
--e; // To match with what our formatter expects.
if (fixed && e != -1)
{
// Oops we actually need a different number of digits to what we asked for:
(*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
digits += e + 1;
if (digits == 0)
{
// We need to get *all* the digits and then possibly round up,
// we end up with either "0" or "1" as the result.
ps = mpf_get_str(0, &e, 10, 0, m_data);
--e;
unsigned offset = *ps == '-' ? 1 : 0;
if (ps[offset] > '5')
{
++e;
ps[offset] = '1';
ps[offset + 1] = 0;
}
else if (ps[offset] == '5')
{
unsigned i = offset + 1;
bool round_up = false;
while (ps[i] != 0)
{
if (ps[i] != '0')
{
round_up = true;
break;
}
++i;
}
if (round_up)
{
++e;
ps[offset] = '1';
ps[offset + 1] = 0;
}
else
{
ps[offset] = '0';
ps[offset + 1] = 0;
}
}
else
{
ps[offset] = '0';
ps[offset + 1] = 0;
}
}
else if (digits > 0)
{
mp_exp_t old_e = e;
ps = mpf_get_str(0, &e, 10, static_cast(digits), m_data);
--e; // To match with what our formatter expects.
if (old_e > e)
{
// in some cases, when we ask for more digits of precision, it will
// change the number of digits to the left of the decimal, if that
// happens, account for it here.
// example: cout << fixed << setprecision(3) << mpf_float_50("99.9809")
digits -= old_e - e;
ps = mpf_get_str(0, &e, 10, static_cast(digits), m_data);
--e; // To match with what our formatter expects.
}
}
else
{
ps = mpf_get_str(0, &e, 10, 1, m_data);
--e;
unsigned offset = *ps == '-' ? 1 : 0;
ps[offset] = '0';
ps[offset + 1] = 0;
}
}
result = ps;
(*free_func_ptr)((void*)ps, std::strlen(ps) + 1);
}
boost::multiprecision::detail::format_float_string(result, e, org_digits, f, mpf_sgn(m_data) == 0);
return result;
}
~gmp_float_imp() BOOST_NOEXCEPT
{
if (m_data[0]._mp_d)
mpf_clear(m_data);
}
void negate() BOOST_NOEXCEPT
{
BOOST_ASSERT(m_data[0]._mp_d);
mpf_neg(m_data, m_data);
}
int compare(const gmp_float& o) const BOOST_NOEXCEPT
{
BOOST_ASSERT(m_data[0]._mp_d && o.m_data[0]._mp_d);
return mpf_cmp(m_data, o.m_data);
}
int compare(long i) const BOOST_NOEXCEPT
{
BOOST_ASSERT(m_data[0]._mp_d);
return mpf_cmp_si(m_data, i);
}
int compare(unsigned long i) const BOOST_NOEXCEPT
{
BOOST_ASSERT(m_data[0]._mp_d);
return mpf_cmp_ui(m_data, i);
}
template
typename enable_if, int>::type compare(V v) const
{
gmp_float d;
d = v;
return compare(d);
}
mpf_t& data() BOOST_NOEXCEPT
{
BOOST_ASSERT(m_data[0]._mp_d);
return m_data;
}
const mpf_t& data() const BOOST_NOEXCEPT
{
BOOST_ASSERT(m_data[0]._mp_d);
return m_data;
}
protected:
mpf_t m_data;
static boost::multiprecision::detail::precision_type& get_default_precision() BOOST_NOEXCEPT
{
static boost::multiprecision::detail::precision_type val(50);
return val;
}
};
} // namespace detail
struct gmp_int;
struct gmp_rational;
template
struct gmp_float : public detail::gmp_float_imp
{
gmp_float()
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
}
gmp_float(const gmp_float& o) : detail::gmp_float_imp(o) {}
template
gmp_float(const gmp_float& o, typename enable_if_c::type* = 0);
template
explicit gmp_float(const gmp_float& o, typename disable_if_c::type* = 0);
gmp_float(const gmp_int& o);
gmp_float(const gmp_rational& o);
gmp_float(const mpf_t val)
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set(this->m_data, val);
}
gmp_float(const mpz_t val)
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set_z(this->m_data, val);
}
gmp_float(const mpq_t val)
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set_q(this->m_data, val);
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_float(gmp_float&& o) BOOST_NOEXCEPT : detail::gmp_float_imp(static_cast&&>(o))
{}
#endif
gmp_float& operator=(const gmp_float& o)
{
*static_cast*>(this) = static_cast const&>(o);
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_float& operator=(gmp_float&& o) BOOST_NOEXCEPT
{
*static_cast*>(this) = static_cast&&>(o);
return *this;
}
#endif
template
gmp_float& operator=(const gmp_float& o);
gmp_float& operator=(const gmp_int& o);
gmp_float& operator=(const gmp_rational& o);
gmp_float& operator=(const mpf_t val)
{
if (this->m_data[0]._mp_d == 0)
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set(this->m_data, val);
return *this;
}
gmp_float& operator=(const mpz_t val)
{
if (this->m_data[0]._mp_d == 0)
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set_z(this->m_data, val);
return *this;
}
gmp_float& operator=(const mpq_t val)
{
if (this->m_data[0]._mp_d == 0)
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set_q(this->m_data, val);
return *this;
}
template
gmp_float& operator=(const V& v)
{
*static_cast*>(this) = v;
return *this;
}
};
template <>
struct gmp_float<0> : public detail::gmp_float_imp<0>
{
//
// We have a problem with mpf_t in that the precision we request isn't what we get.
// As a result the front end can end up chasing it's tail trying to create a variable
// with the the correct precision to hold the result of an expression.
// See: https://github.com/boostorg/multiprecision/issues/164
// The problem is made worse by the fact that our conversions from base10 to 2 and
// vice-versa do not exactly round trip (and probably never will).
// The workaround is to keep track of the precision requested, and always return
// that as the current actual precision.
//
private:
unsigned requested_precision;
public:
gmp_float() : requested_precision(get_default_precision())
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
}
gmp_float(const mpf_t val) : requested_precision(get_default_precision())
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
mpf_set(this->m_data, val);
}
gmp_float(const mpz_t val) : requested_precision(get_default_precision())
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
mpf_set_z(this->m_data, val);
}
gmp_float(const mpq_t val) : requested_precision(get_default_precision())
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
mpf_set_q(this->m_data, val);
}
gmp_float(const gmp_float& o) : detail::gmp_float_imp<0>(o), requested_precision(o.requested_precision) {}
template
gmp_float(const gmp_float& o)
{
mpf_init2(this->m_data, mpf_get_prec(o.data()));
mpf_set(this->m_data, o.data());
requested_precision = D;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_float(gmp_float&& o) BOOST_NOEXCEPT : detail::gmp_float_imp<0>(static_cast&&>(o)), requested_precision(o.requested_precision)
{}
#endif
gmp_float(const gmp_int& o);
gmp_float(const gmp_rational& o);
gmp_float(const gmp_float& o, unsigned digits10) : requested_precision(digits10)
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
mpf_set(this->m_data, o.data());
}
template
gmp_float(const V& o, unsigned digits10) : requested_precision(digits10)
{
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
*this = o;
}
#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
//
// Support for new types in C++17
//
template
gmp_float(const std::basic_string_view& o, unsigned digits10) : requested_precision(digits10)
{
using default_ops::assign_from_string_view;
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10));
assign_from_string_view(*this, o);
}
#endif
gmp_float& operator=(const gmp_float& o)
{
*static_cast*>(this) = static_cast const&>(o);
requested_precision = o.requested_precision;
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_float& operator=(gmp_float&& o) BOOST_NOEXCEPT
{
*static_cast*>(this) = static_cast&&>(o);
requested_precision = o.requested_precision;
return *this;
}
#endif
template
gmp_float& operator=(const gmp_float& o)
{
if (this->m_data[0]._mp_d == 0)
{
mpf_init2(this->m_data, mpf_get_prec(o.data()));
}
else
{
mpf_set_prec(this->m_data, mpf_get_prec(o.data()));
}
mpf_set(this->m_data, o.data());
requested_precision = D;
return *this;
}
gmp_float& operator=(const gmp_int& o);
gmp_float& operator=(const gmp_rational& o);
gmp_float& operator=(const mpf_t val)
{
if (this->m_data[0]._mp_d == 0)
{
requested_precision = get_default_precision();
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
}
mpf_set(this->m_data, val);
return *this;
}
gmp_float& operator=(const mpz_t val)
{
if (this->m_data[0]._mp_d == 0)
{
requested_precision = get_default_precision();
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
}
mpf_set_z(this->m_data, val);
return *this;
}
gmp_float& operator=(const mpq_t val)
{
if (this->m_data[0]._mp_d == 0)
{
requested_precision = get_default_precision();
mpf_init2(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
}
mpf_set_q(this->m_data, val);
return *this;
}
template
gmp_float& operator=(const V& v)
{
*static_cast*>(this) = v;
return *this;
}
static unsigned default_precision() BOOST_NOEXCEPT
{
return get_default_precision();
}
static void default_precision(unsigned v) BOOST_NOEXCEPT
{
get_default_precision() = v;
}
unsigned precision() const BOOST_NOEXCEPT
{
return requested_precision;
}
void precision(unsigned digits10) BOOST_NOEXCEPT
{
requested_precision = digits10;
mpf_set_prec(this->m_data, multiprecision::detail::digits10_2_2(requested_precision));
}
void swap(gmp_float& o)
{
std::swap(requested_precision, o.requested_precision);
gmp_float_imp<0>::swap(o);
}
};
template
inline typename enable_if_c::value, bool>::type eval_eq(const gmp_float& a, const T& b) BOOST_NOEXCEPT
{
return a.compare(b) == 0;
}
template
inline typename enable_if_c::value, bool>::type eval_lt(const gmp_float& a, const T& b) BOOST_NOEXCEPT
{
return a.compare(b) < 0;
}
template
inline typename enable_if_c::value, bool>::type eval_gt(const gmp_float& a, const T& b) BOOST_NOEXCEPT
{
return a.compare(b) > 0;
}
template
inline void eval_add(gmp_float& result, const gmp_float& o)
{
mpf_add(result.data(), result.data(), o.data());
}
template
inline void eval_subtract(gmp_float& result, const gmp_float& o)
{
mpf_sub(result.data(), result.data(), o.data());
}
template
inline void eval_multiply(gmp_float& result, const gmp_float& o)
{
mpf_mul(result.data(), result.data(), o.data());
}
template
inline bool eval_is_zero(const gmp_float& val) BOOST_NOEXCEPT
{
return mpf_sgn(val.data()) == 0;
}
template
inline void eval_divide(gmp_float& result, const gmp_float& o)
{
if (eval_is_zero(o))
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
mpf_div(result.data(), result.data(), o.data());
}
template
inline void eval_add(gmp_float& result, unsigned long i)
{
mpf_add_ui(result.data(), result.data(), i);
}
template
inline void eval_subtract(gmp_float& result, unsigned long i)
{
mpf_sub_ui(result.data(), result.data(), i);
}
template
inline void eval_multiply(gmp_float& result, unsigned long i)
{
mpf_mul_ui(result.data(), result.data(), i);
}
template
inline void eval_divide(gmp_float& result, unsigned long i)
{
if (i == 0)
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
mpf_div_ui(result.data(), result.data(), i);
}
template
inline void eval_add(gmp_float& result, long i)
{
if (i > 0)
mpf_add_ui(result.data(), result.data(), i);
else
mpf_sub_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
}
template
inline void eval_subtract(gmp_float& result, long i)
{
if (i > 0)
mpf_sub_ui(result.data(), result.data(), i);
else
mpf_add_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
}
template
inline void eval_multiply(gmp_float& result, long i)
{
mpf_mul_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
if (i < 0)
mpf_neg(result.data(), result.data());
}
template
inline void eval_divide(gmp_float& result, long i)
{
if (i == 0)
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
mpf_div_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i));
if (i < 0)
mpf_neg(result.data(), result.data());
}
//
// Specialised 3 arg versions of the basic operators:
//
template
inline void eval_add(gmp_float& a, const gmp_float& x, const gmp_float& y)
{
mpf_add(a.data(), x.data(), y.data());
}
template
inline void eval_add(gmp_float& a, const gmp_float& x, unsigned long y)
{
mpf_add_ui(a.data(), x.data(), y);
}
template
inline void eval_add(gmp_float& a, const gmp_float& x, long y)
{
if (y < 0)
mpf_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
else
mpf_add_ui(a.data(), x.data(), y);
}
template
inline void eval_add(gmp_float& a, unsigned long x, const gmp_float& y)
{
mpf_add_ui(a.data(), y.data(), x);
}
template
inline void eval_add(gmp_float& a, long x, const gmp_float& y)
{
if (x < 0)
{
mpf_ui_sub(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
mpf_neg(a.data(), a.data());
}
else
mpf_add_ui(a.data(), y.data(), x);
}
template
inline void eval_subtract(gmp_float& a, const gmp_float& x, const gmp_float& y)
{
mpf_sub(a.data(), x.data(), y.data());
}
template
inline void eval_subtract(gmp_float& a, const gmp_float& x, unsigned long y)
{
mpf_sub_ui(a.data(), x.data(), y);
}
template
inline void eval_subtract(gmp_float& a, const gmp_float& x, long y)
{
if (y < 0)
mpf_add_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
else
mpf_sub_ui(a.data(), x.data(), y);
}
template
inline void eval_subtract(gmp_float& a, unsigned long x, const gmp_float& y)
{
mpf_ui_sub(a.data(), x, y.data());
}
template
inline void eval_subtract(gmp_float& a, long x, const gmp_float& y)
{
if (x < 0)
{
mpf_add_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x));
mpf_neg(a.data(), a.data());
}
else
mpf_ui_sub(a.data(), x, y.data());
}
template
inline void eval_multiply(gmp_float& a, const gmp_float& x, const gmp_float& y)
{
mpf_mul(a.data(), x.data(), y.data());
}
template
inline void eval_multiply(gmp_float& a, const gmp_float& x, unsigned long y)
{
mpf_mul_ui(a.data(), x.data(), y);
}
template
inline void eval_multiply(gmp_float& a, const gmp_float& x, long y)
{
if (y < 0)
{
mpf_mul_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
a.negate();
}
else
mpf_mul_ui(a.data(), x.data(), y);
}
template
inline void eval_multiply(gmp_float& a, unsigned long x, const gmp_float& y)
{
mpf_mul_ui(a.data(), y.data(), x);
}
template
inline void eval_multiply(gmp_float& a, long x, const gmp_float& y)
{
if (x < 0)
{
mpf_mul_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x));
mpf_neg(a.data(), a.data());
}
else
mpf_mul_ui(a.data(), y.data(), x);
}
template
inline void eval_divide(gmp_float& a, const gmp_float& x, const gmp_float& y)
{
if (eval_is_zero(y))
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
mpf_div(a.data(), x.data(), y.data());
}
template
inline void eval_divide(gmp_float& a, const gmp_float& x, unsigned long y)
{
if (y == 0)
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
mpf_div_ui(a.data(), x.data(), y);
}
template
inline void eval_divide(gmp_float& a, const gmp_float& x, long y)
{
if (y == 0)
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
if (y < 0)
{
mpf_div_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y));
a.negate();
}
else
mpf_div_ui(a.data(), x.data(), y);
}
template
inline void eval_divide(gmp_float& a, unsigned long x, const gmp_float& y)
{
if (eval_is_zero(y))
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
mpf_ui_div(a.data(), x, y.data());
}
template
inline void eval_divide(gmp_float& a, long x, const gmp_float& y)
{
if (eval_is_zero(y))
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
if (x < 0)
{
mpf_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data());
mpf_neg(a.data(), a.data());
}
else
mpf_ui_div(a.data(), x, y.data());
}
template
inline int eval_get_sign(const gmp_float& val) BOOST_NOEXCEPT
{
return mpf_sgn(val.data());
}
template
inline void eval_convert_to(unsigned long* result, const gmp_float& val) BOOST_NOEXCEPT
{
if (0 == mpf_fits_ulong_p(val.data()))
*result = (std::numeric_limits::max)();
else
*result = (unsigned long)mpf_get_ui(val.data());
}
template
inline void eval_convert_to(long* result, const gmp_float& val) BOOST_NOEXCEPT
{
if (0 == mpf_fits_slong_p(val.data()))
{
*result = (std::numeric_limits::max)();
*result *= mpf_sgn(val.data());
}
else
*result = (long)mpf_get_si(val.data());
}
template
inline void eval_convert_to(double* result, const gmp_float& val) BOOST_NOEXCEPT
{
*result = mpf_get_d(val.data());
}
#ifdef BOOST_HAS_LONG_LONG
template
inline void eval_convert_to(boost::long_long_type* result, const gmp_float& val)
{
gmp_float t(val);
if (eval_get_sign(t) < 0)
t.negate();
long digits = std::numeric_limits::digits - std::numeric_limits::digits;
if (digits > 0)
mpf_div_2exp(t.data(), t.data(), digits);
if (!mpf_fits_slong_p(t.data()))
{
if (eval_get_sign(val) < 0)
*result = (std::numeric_limits::min)();
else
*result = (std::numeric_limits::max)();
return;
};
*result = mpf_get_si(t.data());
while (digits > 0)
{
*result <<= digits;
digits -= std::numeric_limits::digits;
mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits::digits : std::numeric_limits::digits + digits);
unsigned long l = (unsigned long)mpf_get_ui(t.data());
if (digits < 0)
l >>= -digits;
*result |= l;
}
if (eval_get_sign(val) < 0)
*result = -*result;
}
template
inline void eval_convert_to(boost::ulong_long_type* result, const gmp_float& val)
{
gmp_float t(val);
long digits = std::numeric_limits::digits - std::numeric_limits::digits;
if (digits > 0)
mpf_div_2exp(t.data(), t.data(), digits);
if (!mpf_fits_ulong_p(t.data()))
{
*result = (std::numeric_limits::max)();
return;
}
*result = mpf_get_ui(t.data());
while (digits > 0)
{
*result <<= digits;
digits -= std::numeric_limits::digits;
mpf_mul_2exp(t.data(), t.data(), digits >= 0 ? std::numeric_limits::digits : std::numeric_limits::digits + digits);
unsigned long l = (unsigned long)mpf_get_ui(t.data());
if (digits < 0)
l >>= -digits;
*result |= l;
}
}
#endif
//
// Native non-member operations:
//
template
inline void eval_sqrt(gmp_float& result, const gmp_float& val)
{
mpf_sqrt(result.data(), val.data());
}
template
inline void eval_abs(gmp_float& result, const gmp_float& val)
{
mpf_abs(result.data(), val.data());
}
template
inline void eval_fabs(gmp_float& result, const gmp_float& val)
{
mpf_abs(result.data(), val.data());
}
template
inline void eval_ceil(gmp_float& result, const gmp_float& val)
{
mpf_ceil(result.data(), val.data());
}
template
inline void eval_floor(gmp_float& result, const gmp_float& val)
{
mpf_floor(result.data(), val.data());
}
template
inline void eval_trunc(gmp_float& result, const gmp_float& val)
{
mpf_trunc(result.data(), val.data());
}
template
inline void eval_ldexp(gmp_float& result, const gmp_float& val, long e)
{
if (e > 0)
mpf_mul_2exp(result.data(), val.data(), e);
else if (e < 0)
mpf_div_2exp(result.data(), val.data(), -e);
else
result = val;
}
template
inline void eval_frexp(gmp_float& result, const gmp_float& val, int* e)
{
#if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
mpir_si v;
mpf_get_d_2exp(&v, val.data());
#else
long v;
mpf_get_d_2exp(&v, val.data());
#endif
*e = v;
eval_ldexp(result, val, -v);
}
template
inline void eval_frexp(gmp_float& result, const gmp_float& val, long* e)
{
#if (BOOST_MP_MPIR_VERSION >= 20600) && (BOOST_MP_MPIR_VERSION < 30000)
mpir_si v;
mpf_get_d_2exp(&v, val.data());
*e = v;
eval_ldexp(result, val, -v);
#else
mpf_get_d_2exp(e, val.data());
eval_ldexp(result, val, -*e);
#endif
}
template
inline std::size_t hash_value(const gmp_float& val)
{
std::size_t result = 0;
for (int i = 0; i < std::abs(val.data()[0]._mp_size); ++i)
boost::hash_combine(result, val.data()[0]._mp_d[i]);
boost::hash_combine(result, val.data()[0]._mp_exp);
boost::hash_combine(result, val.data()[0]._mp_size);
return result;
}
struct gmp_int
{
#ifdef BOOST_HAS_LONG_LONG
typedef mpl::list signed_types;
typedef mpl::list unsigned_types;
#else
typedef mpl::list signed_types;
typedef mpl::list unsigned_types;
#endif
typedef mpl::list float_types;
gmp_int()
{
mpz_init(this->m_data);
}
gmp_int(const gmp_int& o)
{
if (o.m_data[0]._mp_d)
mpz_init_set(m_data, o.m_data);
else
mpz_init(this->m_data);
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_int(gmp_int&& o) BOOST_NOEXCEPT
{
m_data[0] = o.m_data[0];
o.m_data[0]._mp_d = 0;
}
#endif
explicit gmp_int(const mpf_t val)
{
mpz_init(this->m_data);
mpz_set_f(this->m_data, val);
}
gmp_int(const mpz_t val)
{
mpz_init_set(this->m_data, val);
}
explicit gmp_int(const mpq_t val)
{
mpz_init(this->m_data);
mpz_set_q(this->m_data, val);
}
template
explicit gmp_int(const gmp_float& o)
{
mpz_init(this->m_data);
mpz_set_f(this->m_data, o.data());
}
explicit gmp_int(const gmp_rational& o);
gmp_int& operator=(const gmp_int& o)
{
if (m_data[0]._mp_d == 0)
mpz_init(this->m_data);
mpz_set(m_data, o.m_data);
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
gmp_int& operator=(gmp_int&& o) BOOST_NOEXCEPT
{
mpz_swap(m_data, o.m_data);
return *this;
}
#endif
#ifdef BOOST_HAS_LONG_LONG
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
gmp_int& operator=(boost::ulong_long_type i)
{
*this = static_cast(i);
return *this;
}
#else
gmp_int& operator=(boost::ulong_long_type i)
{
if (m_data[0]._mp_d == 0)
mpz_init(this->m_data);
boost::ulong_long_type mask = ((((1uLL << (std::numeric_limits::digits - 1)) - 1) << 1) | 1uLL);
unsigned shift = 0;
mpz_t t;
mpz_set_ui(m_data, 0);
mpz_init_set_ui(t, 0);
while (i)
{
mpz_set_ui(t, static_cast