- boost v1.68 for linux
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2018 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_MP_COMPLEX128_HPP
|
||||
#define BOOST_MP_COMPLEX128_HPP
|
||||
|
||||
#include <boost/multiprecision/float128.hpp>
|
||||
#include <boost/multiprecision/complex_adaptor.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
|
||||
typedef number<complex_adaptor<float128_backend>, et_off> complex128;
|
||||
|
||||
template <>
|
||||
struct component_type<number<complex_adaptor<float128_backend> > >
|
||||
{
|
||||
typedef float128 type;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,853 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2018 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_MULTIPRECISION_COMPLEX_ADAPTOR_HPP
|
||||
#define BOOST_MULTIPRECISION_COMPLEX_ADAPTOR_HPP
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/multiprecision/detail/digits.hpp>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/type_traits/is_complex.hpp>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace backends{
|
||||
|
||||
template <class Backend>
|
||||
struct complex_adaptor
|
||||
{
|
||||
protected:
|
||||
Backend m_real, m_imag;
|
||||
public:
|
||||
Backend& real_data()
|
||||
{
|
||||
return m_real;
|
||||
}
|
||||
const Backend& real_data() const
|
||||
{
|
||||
return m_real;
|
||||
}
|
||||
Backend& imag_data()
|
||||
{
|
||||
return m_imag;
|
||||
}
|
||||
const Backend& imag_data() const
|
||||
{
|
||||
return m_imag;
|
||||
}
|
||||
|
||||
typedef typename Backend::signed_types signed_types;
|
||||
typedef typename Backend::unsigned_types unsigned_types;
|
||||
typedef typename Backend::float_types float_types;
|
||||
typedef typename Backend::exponent_type exponent_type;
|
||||
|
||||
complex_adaptor() {}
|
||||
complex_adaptor(const complex_adaptor& o) : m_real(o.real_data()), m_imag(o.imag_data()) {}
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
complex_adaptor(complex_adaptor&& o) : m_real(std::move(o.real_data())), m_imag(std::move(o.imag_data())) {}
|
||||
#endif
|
||||
complex_adaptor(const Backend& val)
|
||||
: m_real(val) {}
|
||||
|
||||
complex_adaptor(const std::complex<float>& val)
|
||||
{
|
||||
m_real = (long double)val.real();
|
||||
m_imag = (long double)val.imag();
|
||||
}
|
||||
complex_adaptor(const std::complex<double>& val)
|
||||
{
|
||||
m_real = (long double)val.real();
|
||||
m_imag = (long double)val.imag();
|
||||
}
|
||||
complex_adaptor(const std::complex<long double>& val)
|
||||
{
|
||||
m_real = val.real();
|
||||
m_imag = val.imag();
|
||||
}
|
||||
|
||||
complex_adaptor& operator=(const complex_adaptor& o)
|
||||
{
|
||||
m_real = o.real_data();
|
||||
m_imag = o.imag_data();
|
||||
return *this;
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
complex_adaptor& operator=(complex_adaptor&& o) BOOST_NOEXCEPT
|
||||
{
|
||||
m_real = std::move(o.real_data());
|
||||
m_imag = std::move(o.imag_data());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
template <class V>
|
||||
complex_adaptor& operator=(const V& v)
|
||||
{
|
||||
typedef typename mpl::front<unsigned_types>::type ui_type;
|
||||
m_real = v;
|
||||
m_imag = ui_type(0u);
|
||||
return *this;
|
||||
}
|
||||
template <class T>
|
||||
complex_adaptor& operator=(const std::complex<T>& val)
|
||||
{
|
||||
m_real = (long double)val.real();
|
||||
m_imag = (long double)val.imag();
|
||||
return *this;
|
||||
}
|
||||
complex_adaptor& operator = (const char* s)
|
||||
{
|
||||
using default_ops::eval_fpclassify;
|
||||
|
||||
if (s && (*s == '('))
|
||||
{
|
||||
std::string part;
|
||||
const char* p = ++s;
|
||||
while (*p && (*p != ',') && (*p != ')'))
|
||||
++p;
|
||||
part.assign(s + 1, p);
|
||||
real_data() = part.c_str();
|
||||
s = p;
|
||||
if (*p && (*p != '}'))
|
||||
{
|
||||
++p;
|
||||
while (*p && (*p != ',') && (*p != ')'))
|
||||
++p;
|
||||
part.assign(s + 1, p);
|
||||
}
|
||||
else
|
||||
part.erase();
|
||||
imag_data() = part.c_str();
|
||||
|
||||
if (eval_fpclassify(imag_data()) == (int)FP_NAN)
|
||||
{
|
||||
real_data() = imag_data();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef typename mpl::front<unsigned_types>::type ui_type;
|
||||
ui_type zero = 0u;
|
||||
real_data() = s;
|
||||
imag_data() = zero;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int compare(const complex_adaptor& o)const
|
||||
{
|
||||
// They are either equal or not:
|
||||
return (m_real.compare(o.real_data()) == 0) && (m_imag.compare(o.imag_data()) == 0) ? 0 : 1;
|
||||
}
|
||||
template <class T>
|
||||
int compare(const T& val)const
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
return (m_real.compare(val) == 0) && eval_is_zero(m_imag) ? 0 : 1;
|
||||
}
|
||||
void swap(complex_adaptor& o)
|
||||
{
|
||||
real_data().swap(o.real_data());
|
||||
imag_data().swap(o.imag_data());
|
||||
}
|
||||
std::string str(std::streamsize dig, std::ios_base::fmtflags f)const
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
if (eval_is_zero(imag_data()))
|
||||
return m_real.str(dig, f);
|
||||
return "(" + m_real.str(dig, f) + "," + m_imag.str(dig, f) + ")";
|
||||
}
|
||||
void negate()
|
||||
{
|
||||
m_real.negate();
|
||||
m_imag.negate();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Backend, class T>
|
||||
inline typename enable_if<is_arithmetic<T>, bool>::type eval_eq(const complex_adaptor<Backend>& a, const T& b) BOOST_NOEXCEPT
|
||||
{
|
||||
return a.compare(b) == 0;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
|
||||
{
|
||||
eval_add(result.real_data(), o.real_data());
|
||||
eval_add(result.imag_data(), o.imag_data());
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
|
||||
{
|
||||
eval_subtract(result.real_data(), o.real_data());
|
||||
eval_subtract(result.imag_data(), o.imag_data());
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& o)
|
||||
{
|
||||
Backend t1, t2, t3;
|
||||
eval_multiply(t1, result.real_data(), o.real_data());
|
||||
eval_multiply(t2, result.imag_data(), o.imag_data());
|
||||
eval_subtract(t3, t1, t2);
|
||||
eval_multiply(t1, result.real_data(), o.imag_data());
|
||||
eval_multiply(t2, result.imag_data(), o.real_data());
|
||||
eval_add(t1, t2);
|
||||
result.real_data() = BOOST_MP_MOVE(t3);
|
||||
result.imag_data() = BOOST_MP_MOVE(t1);
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& z)
|
||||
{
|
||||
// (a+bi) / (c + di)
|
||||
using default_ops::eval_fabs;
|
||||
using default_ops::eval_divide;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_is_zero;
|
||||
Backend t1, t2;
|
||||
|
||||
if (eval_is_zero(z.imag_data()))
|
||||
{
|
||||
eval_divide(result.real_data(), z.real_data());
|
||||
eval_divide(result.imag_data(), z.real_data());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
eval_fabs(t1, z.real_data());
|
||||
eval_fabs(t2, z.imag_data());
|
||||
if (t1.compare(t2) < 0)
|
||||
{
|
||||
eval_divide(t1, z.real_data(), z.imag_data()); // t1 = c/d
|
||||
eval_multiply(t2, z.real_data(), t1);
|
||||
eval_add(t2, z.imag_data()); // denom = c * (c/d) + d
|
||||
Backend t_real(result.real_data());
|
||||
// real = (a * (c/d) + b) / (denom)
|
||||
eval_multiply(result.real_data(), t1);
|
||||
eval_add(result.real_data(), result.imag_data());
|
||||
eval_divide(result.real_data(), t2);
|
||||
// imag = (b * c/d - a) / denom
|
||||
eval_multiply(result.imag_data(), t1);
|
||||
eval_subtract(result.imag_data(), t_real);
|
||||
eval_divide(result.imag_data(), t2);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_divide(t1, z.imag_data(), z.real_data()); // t1 = d/c
|
||||
eval_multiply(t2, z.imag_data(), t1);
|
||||
eval_add(t2, z.real_data()); // denom = d * d/c + c
|
||||
|
||||
Backend r_t(result.real_data());
|
||||
Backend i_t(result.imag_data());
|
||||
|
||||
// real = (b * d/c + a) / denom
|
||||
eval_multiply(result.real_data(), result.imag_data(), t1);
|
||||
eval_add(result.real_data(), r_t);
|
||||
eval_divide(result.real_data(), t2);
|
||||
// imag = (-a * d/c + b) / denom
|
||||
eval_multiply(result.imag_data(), r_t, t1);
|
||||
result.imag_data().negate();
|
||||
eval_add(result.imag_data(), i_t);
|
||||
eval_divide(result.imag_data(), t2);
|
||||
}
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.real_data(), scalar);
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.real_data(), scalar);
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.real_data(), scalar);
|
||||
eval_multiply(result.imag_data(), scalar);
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.real_data(), scalar);
|
||||
eval_divide(result.imag_data(), scalar);
|
||||
}
|
||||
// Optimised 3 arg versions:
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_add(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.real_data(), a.real_data(), scalar);
|
||||
result.imag_data() = a.imag_data();
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_subtract(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.real_data(), a.real_data(), scalar);
|
||||
result.imag_data() = a.imag_data();
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_multiply(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.real_data(), a.real_data(), scalar);
|
||||
eval_multiply(result.imag_data(), a.imag_data(), scalar);
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline typename boost::disable_if_c<boost::is_same<complex_adaptor<Backend>, T>::value>::type eval_divide(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& a, const T& scalar)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.real_data(), a.real_data(), scalar);
|
||||
eval_divide(result.imag_data(), a.imag_data(), scalar);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline bool eval_is_zero(const complex_adaptor<Backend>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
return eval_is_zero(val.real_data()) && eval_is_zero(val.imag_data());
|
||||
}
|
||||
template <class Backend>
|
||||
inline int eval_get_sign(const complex_adaptor<Backend>&)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(Backend) == UINT_MAX, "Complex numbers have no sign bit."); // designed to always fail
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Result, class Backend>
|
||||
inline typename disable_if_c<boost::is_complex<Result>::value>::type eval_convert_to(Result* result, const complex_adaptor<Backend>& val)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_convert_to;
|
||||
if (!eval_is_zero(val.imag_data()))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar."));
|
||||
}
|
||||
eval_convert_to(result, val.real_data());
|
||||
}
|
||||
|
||||
template <class Backend, class T>
|
||||
inline void assign_components(complex_adaptor<Backend>& result, const T& a, const T& b)
|
||||
{
|
||||
result.real_data() = a;
|
||||
result.imag_data() = b;
|
||||
}
|
||||
|
||||
//
|
||||
// Native non-member operations:
|
||||
//
|
||||
template <class Backend>
|
||||
inline void eval_sqrt(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& val)
|
||||
{
|
||||
// Use the following:
|
||||
// sqrt(z) = (s, zi / 2s) for zr >= 0
|
||||
// (|zi| / 2s, +-s) for zr < 0
|
||||
// where s = sqrt{ [ |zr| + sqrt(zr^2 + zi^2) ] / 2 },
|
||||
// and the +- sign is the same as the sign of zi.
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_abs;
|
||||
using default_ops::eval_divide;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_is_zero;
|
||||
|
||||
if (eval_is_zero(val.imag_data()) && (eval_get_sign(val.real_data())>= 0))
|
||||
{
|
||||
static const typename mpl::front<typename Backend::unsigned_types>::type zero = 0u;
|
||||
eval_sqrt(result.real_data(), val.real_data());
|
||||
result.imag_data() = zero;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool __my_real_part_is_neg(eval_get_sign(val.real_data()) < 0);
|
||||
|
||||
Backend __my_real_part_fabs(val.real_data());
|
||||
if (__my_real_part_is_neg)
|
||||
__my_real_part_fabs.negate();
|
||||
|
||||
Backend t, __my_sqrt_part;
|
||||
eval_abs(__my_sqrt_part, val);
|
||||
eval_add(__my_sqrt_part, __my_real_part_fabs);
|
||||
eval_ldexp(t, __my_sqrt_part, -1);
|
||||
eval_sqrt(__my_sqrt_part, t);
|
||||
|
||||
if (__my_real_part_is_neg == false)
|
||||
{
|
||||
eval_ldexp(t, __my_sqrt_part, 1);
|
||||
eval_divide(result.imag_data(), val.imag_data(), t);
|
||||
result.real_data() = __my_sqrt_part;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool __my_imag_part_is_neg(eval_get_sign(val.imag_data()) < 0);
|
||||
|
||||
Backend __my_imag_part_fabs(val.imag_data());
|
||||
if (__my_imag_part_is_neg)
|
||||
__my_imag_part_fabs.negate();
|
||||
|
||||
eval_ldexp(t, __my_sqrt_part, 1);
|
||||
eval_divide(result.real_data(), __my_imag_part_fabs, t);
|
||||
if (__my_imag_part_is_neg)
|
||||
__my_sqrt_part.negate();
|
||||
result.imag_data() = __my_sqrt_part;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_abs(Backend& result, const complex_adaptor<Backend>& val)
|
||||
{
|
||||
Backend t1, t2;
|
||||
eval_multiply(t1, val.real_data(), val.real_data());
|
||||
eval_multiply(t2, val.imag_data(), val.imag_data());
|
||||
eval_add(t1, t2);
|
||||
eval_sqrt(result, t1);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_pow(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& b, const complex_adaptor<Backend>& e)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_acos;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_exp;
|
||||
using default_ops::eval_cos;
|
||||
using default_ops::eval_sin;
|
||||
|
||||
if (eval_is_zero(e))
|
||||
{
|
||||
typename mpl::front<typename Backend::unsigned_types>::type one(1);
|
||||
result = one;
|
||||
return;
|
||||
}
|
||||
else if (eval_is_zero(b))
|
||||
{
|
||||
if (eval_is_zero(e.real_data()))
|
||||
{
|
||||
Backend n = std::numeric_limits<number<Backend> >::quiet_NaN().backend();
|
||||
result.real_data() = n;
|
||||
result.imag_data() = n;
|
||||
}
|
||||
else if (eval_get_sign(e.real_data()) < 0)
|
||||
{
|
||||
Backend n = std::numeric_limits<number<Backend> >::infinity().backend();
|
||||
result.real_data() = n;
|
||||
typename mpl::front<typename Backend::unsigned_types>::type zero(0);
|
||||
if (eval_is_zero(e.imag_data()))
|
||||
result.imag_data() = zero;
|
||||
else
|
||||
result.imag_data() = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
typename mpl::front<typename Backend::unsigned_types>::type zero(0);
|
||||
result = zero;
|
||||
}
|
||||
return;
|
||||
}
|
||||
complex_adaptor<Backend> t;
|
||||
eval_log(t, b);
|
||||
eval_multiply(t, e);
|
||||
eval_exp(result, t);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_exp(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_sin;
|
||||
using default_ops::eval_cos;
|
||||
using default_ops::eval_exp;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_is_zero;
|
||||
|
||||
if (eval_is_zero(arg.imag_data()))
|
||||
{
|
||||
eval_exp(result.real_data(), arg.real_data());
|
||||
typename mpl::front<typename Backend::unsigned_types>::type zero(0);
|
||||
result.imag_data() = zero;
|
||||
return;
|
||||
}
|
||||
eval_cos(result.real_data(), arg.imag_data());
|
||||
eval_sin(result.imag_data(), arg.imag_data());
|
||||
Backend e;
|
||||
eval_exp(e, arg.real_data());
|
||||
if (eval_is_zero(result.real_data()))
|
||||
eval_multiply(result.imag_data(), e);
|
||||
else if (eval_is_zero(result.imag_data()))
|
||||
eval_multiply(result.real_data(), e);
|
||||
else
|
||||
eval_multiply(result, e);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_log(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_log;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_atan2;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
if (eval_is_zero(arg.imag_data()) && (eval_get_sign(arg.real_data()) >= 0))
|
||||
{
|
||||
eval_log(result.real_data(), arg.real_data());
|
||||
typename mpl::front<typename Backend::unsigned_types>::type zero(0);
|
||||
result.imag_data() = zero;
|
||||
return;
|
||||
}
|
||||
|
||||
Backend t1, t2;
|
||||
eval_multiply(t1, arg.real_data(), arg.real_data());
|
||||
eval_multiply(t2, arg.imag_data(), arg.imag_data());
|
||||
eval_add(t1, t2);
|
||||
eval_log(t2, t1);
|
||||
eval_ldexp(result.real_data(), t2, -1);
|
||||
eval_atan2(result.imag_data(), arg.imag_data(), arg.real_data());
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_log10(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_log;
|
||||
using default_ops::eval_divide;
|
||||
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
|
||||
Backend ten;
|
||||
ten = ui_type(10);
|
||||
Backend l_ten;
|
||||
eval_log(l_ten, ten);
|
||||
eval_log(result, arg);
|
||||
eval_divide(result, l_ten);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_sin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_sin;
|
||||
using default_ops::eval_cos;
|
||||
using default_ops::eval_sinh;
|
||||
using default_ops::eval_cosh;
|
||||
|
||||
Backend t1, t2;
|
||||
eval_sin(t1, arg.real_data());
|
||||
eval_cosh(t2, arg.imag_data());
|
||||
eval_multiply(result.real_data(), t1, t2);
|
||||
|
||||
eval_cos(t1, arg.real_data());
|
||||
eval_sinh(t2, arg.imag_data());
|
||||
eval_multiply(result.imag_data(), t1, t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_cos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_sin;
|
||||
using default_ops::eval_cos;
|
||||
using default_ops::eval_sinh;
|
||||
using default_ops::eval_cosh;
|
||||
|
||||
Backend t1, t2;
|
||||
eval_cos(t1, arg.real_data());
|
||||
eval_cosh(t2, arg.imag_data());
|
||||
eval_multiply(result.real_data(), t1, t2);
|
||||
|
||||
eval_sin(t1, arg.real_data());
|
||||
eval_sinh(t2, arg.imag_data());
|
||||
eval_multiply(result.imag_data(), t1, t2);
|
||||
result.imag_data().negate();
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_tan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
complex_adaptor<Backend> c;
|
||||
eval_cos(c, arg);
|
||||
eval_sin(result, arg);
|
||||
eval_divide(result, c);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_asin(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_multiply;
|
||||
|
||||
if (eval_is_zero(arg))
|
||||
{
|
||||
result = arg;
|
||||
return;
|
||||
}
|
||||
|
||||
complex_adaptor<Backend> t1, t2;
|
||||
assign_components(t1, arg.imag_data(), arg.real_data());
|
||||
t1.real_data().negate();
|
||||
eval_asinh(t2, t1);
|
||||
|
||||
assign_components(result, t2.imag_data(), t2.real_data());
|
||||
result.imag_data().negate();
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_acos(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
|
||||
using default_ops::eval_asin;
|
||||
|
||||
Backend half_pi, t1;
|
||||
t1 = static_cast<ui_type>(1u);
|
||||
eval_asin(half_pi, t1);
|
||||
eval_asin(result, arg);
|
||||
result.negate();
|
||||
eval_add(result.real_data(), half_pi);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_atan(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
ui_type one = (ui_type)1u;
|
||||
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_log;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_is_zero;
|
||||
|
||||
complex_adaptor<Backend> __my_z_times_i, t1, t2, t3;
|
||||
assign_components(__my_z_times_i, arg.imag_data(), arg.real_data());
|
||||
__my_z_times_i.real_data().negate();
|
||||
|
||||
eval_add(t1, __my_z_times_i, one);
|
||||
eval_log(t2, t1);
|
||||
eval_subtract(t1, one, __my_z_times_i);
|
||||
eval_log(t3, t1);
|
||||
eval_subtract(t1, t3, t2);
|
||||
|
||||
eval_ldexp(result.real_data(), t1.imag_data(), -1);
|
||||
eval_ldexp(result.imag_data(), t1.real_data(), -1);
|
||||
if(!eval_is_zero(result.real_data()))
|
||||
result.real_data().negate();
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_sinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_sin;
|
||||
using default_ops::eval_cos;
|
||||
using default_ops::eval_sinh;
|
||||
using default_ops::eval_cosh;
|
||||
|
||||
Backend t1, t2;
|
||||
eval_cos(t1, arg.imag_data());
|
||||
eval_sinh(t2, arg.real_data());
|
||||
eval_multiply(result.real_data(), t1, t2);
|
||||
|
||||
eval_cosh(t1, arg.real_data());
|
||||
eval_sin(t2, arg.imag_data());
|
||||
eval_multiply(result.imag_data(), t1, t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_cosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_sin;
|
||||
using default_ops::eval_cos;
|
||||
using default_ops::eval_sinh;
|
||||
using default_ops::eval_cosh;
|
||||
|
||||
Backend t1, t2;
|
||||
eval_cos(t1, arg.imag_data());
|
||||
eval_cosh(t2, arg.real_data());
|
||||
eval_multiply(result.real_data(), t1, t2);
|
||||
|
||||
eval_sin(t1, arg.imag_data());
|
||||
eval_sinh(t2, arg.real_data());
|
||||
eval_multiply(result.imag_data(), t1, t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_tanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
complex_adaptor<Backend> s, c;
|
||||
eval_sinh(s, arg);
|
||||
eval_cosh(c, arg);
|
||||
eval_divide(result, s, c);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_asinh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
ui_type one = (ui_type)1u;
|
||||
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_log;
|
||||
using default_ops::eval_multiply;
|
||||
|
||||
complex_adaptor<Backend> t1, t2;
|
||||
eval_multiply(t1, arg, arg);
|
||||
eval_add(t1, one);
|
||||
eval_sqrt(t2, t1);
|
||||
eval_add(t2, arg);
|
||||
eval_log(result, t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_acosh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
ui_type one = (ui_type)1u;
|
||||
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_log;
|
||||
using default_ops::eval_divide;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_multiply;
|
||||
|
||||
complex_adaptor<Backend> __my_zp(arg);
|
||||
eval_add(__my_zp.real_data(), one);
|
||||
complex_adaptor<Backend> __my_zm(arg);
|
||||
eval_subtract(__my_zm.real_data(), one);
|
||||
|
||||
complex_adaptor<Backend> t1, t2;
|
||||
eval_divide(t1, __my_zm, __my_zp);
|
||||
eval_sqrt(t2, t1);
|
||||
eval_multiply(t2, __my_zp);
|
||||
eval_add(t2, arg);
|
||||
eval_log(result, t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_atanh(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
ui_type one = (ui_type)1u;
|
||||
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_log;
|
||||
using default_ops::eval_divide;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_multiply;
|
||||
|
||||
complex_adaptor<Backend> t1, t2, t3;
|
||||
eval_add(t1, arg, one);
|
||||
eval_log(t2, t1);
|
||||
eval_subtract(t1, one, arg);
|
||||
eval_log(t3, t1);
|
||||
eval_subtract(t2, t3);
|
||||
|
||||
eval_ldexp(result.real_data(), t2.real_data(), -1);
|
||||
eval_ldexp(result.imag_data(), t2.imag_data(), -1);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_conj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
result = arg;
|
||||
result.imag_data().negate();
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_proj(complex_adaptor<Backend>& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
ui_type zero = (ui_type)0u;
|
||||
|
||||
int c1 = eval_fpclassify(arg.real_data());
|
||||
int c2 = eval_fpclassify(arg.imag_data());
|
||||
if (c1 == FP_INFINITE)
|
||||
{
|
||||
result.real_data() = arg.real_data();
|
||||
if (eval_get_sign(result.real_data()) < 0)
|
||||
result.real_data().negate();
|
||||
result.imag_data() = zero;
|
||||
if (eval_get_sign(arg.imag_data()) < 0)
|
||||
result.imag_data().negate();
|
||||
}
|
||||
else if (c2 == FP_INFINITE)
|
||||
{
|
||||
result.real_data() = arg.imag_data();
|
||||
if (eval_get_sign(result.real_data()) < 0)
|
||||
result.real_data().negate();
|
||||
result.imag_data() = zero;
|
||||
if (eval_get_sign(arg.imag_data()) < 0)
|
||||
result.imag_data().negate();
|
||||
}
|
||||
else
|
||||
result = arg;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_real(Backend& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
result = arg.real_data();
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_imag(Backend& result, const complex_adaptor<Backend>& arg)
|
||||
{
|
||||
result = arg.imag_data();
|
||||
}
|
||||
|
||||
template <class Backend, class T>
|
||||
inline void eval_set_imag(complex_adaptor<Backend>& result, const T& arg)
|
||||
{
|
||||
result.imag_data() = arg;
|
||||
}
|
||||
|
||||
template <class Backend, class T>
|
||||
inline void eval_set_real(complex_adaptor<Backend>& result, const T& arg)
|
||||
{
|
||||
result.real_data() = arg;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline std::size_t hash_value(const complex_adaptor<Backend>& val)
|
||||
{
|
||||
std::size_t result = hash_value(val.real_data());
|
||||
std::size_t result2 = hash_value(val.imag_data());
|
||||
boost::hash_combine(result, result2);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace backends
|
||||
|
||||
|
||||
using boost::multiprecision::backends::complex_adaptor;
|
||||
|
||||
template <class Backend>
|
||||
struct number_category<complex_adaptor<Backend> > : public boost::mpl::int_<boost::multiprecision::number_kind_complex> {};
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
struct component_type<number<complex_adaptor<Backend>, ExpressionTemplates> >
|
||||
{
|
||||
typedef number<Backend, ExpressionTemplates> type;
|
||||
};
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
struct complex_result_from_scalar<number<Backend, ExpressionTemplates> >
|
||||
{
|
||||
typedef number<complex_adaptor<Backend>, ExpressionTemplates> type;
|
||||
};
|
||||
|
||||
|
||||
} // namespace multiprecision
|
||||
|
||||
} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MATH_CONCEPTS_ER_HPP
|
||||
#define BOOST_MATH_CONCEPTS_ER_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cmath>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/mpl/list.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace concepts{
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
struct number_backend_float_architype
|
||||
{
|
||||
typedef mpl::list<boost::long_long_type> signed_types;
|
||||
typedef mpl::list<boost::ulong_long_type> unsigned_types;
|
||||
typedef mpl::list<long double> float_types;
|
||||
typedef int exponent_type;
|
||||
|
||||
number_backend_float_architype()
|
||||
{
|
||||
m_value = 0;
|
||||
std::cout << "Default construct" << std::endl;
|
||||
}
|
||||
number_backend_float_architype(const number_backend_float_architype& o)
|
||||
{
|
||||
std::cout << "Copy construct" << std::endl;
|
||||
m_value = o.m_value;
|
||||
}
|
||||
number_backend_float_architype& operator = (const number_backend_float_architype& o)
|
||||
{
|
||||
m_value = o.m_value;
|
||||
std::cout << "Assignment (" << m_value << ")" << std::endl;
|
||||
return *this;
|
||||
}
|
||||
number_backend_float_architype& operator = (boost::ulong_long_type i)
|
||||
{
|
||||
m_value = i;
|
||||
std::cout << "UInt Assignment (" << i << ")" << std::endl;
|
||||
return *this;
|
||||
}
|
||||
number_backend_float_architype& operator = (boost::long_long_type i)
|
||||
{
|
||||
m_value = i;
|
||||
std::cout << "Int Assignment (" << i << ")" << std::endl;
|
||||
return *this;
|
||||
}
|
||||
number_backend_float_architype& operator = (long double d)
|
||||
{
|
||||
m_value = d;
|
||||
std::cout << "long double Assignment (" << d << ")" << std::endl;
|
||||
return *this;
|
||||
}
|
||||
number_backend_float_architype& operator = (const char* s)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
m_value = boost::lexical_cast<long double>(s);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Unable to parse input string: \"") + s + std::string("\" as a valid floating point number.")));
|
||||
}
|
||||
#endif
|
||||
std::cout << "const char* Assignment (" << s << ")" << std::endl;
|
||||
return *this;
|
||||
}
|
||||
void swap(number_backend_float_architype& o)
|
||||
{
|
||||
std::cout << "Swapping (" << m_value << " with " << o.m_value << ")" << std::endl;
|
||||
std::swap(m_value, o.m_value);
|
||||
}
|
||||
std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.flags(f);
|
||||
if(digits)
|
||||
ss.precision(digits);
|
||||
else
|
||||
ss.precision(std::numeric_limits<long double>::digits10 + 3);
|
||||
boost::intmax_t i = m_value;
|
||||
boost::uintmax_t u = m_value;
|
||||
if(!(f & std::ios_base::scientific) && m_value == i)
|
||||
ss << i;
|
||||
else if(!(f & std::ios_base::scientific) && m_value == u)
|
||||
ss << u;
|
||||
else
|
||||
ss << m_value;
|
||||
std::string s = ss.str();
|
||||
std::cout << "Converting to string (" << s << ")" << std::endl;
|
||||
return s;
|
||||
}
|
||||
void negate()
|
||||
{
|
||||
std::cout << "Negating (" << m_value << ")" << std::endl;
|
||||
m_value = -m_value;
|
||||
}
|
||||
int compare(const number_backend_float_architype& o)const
|
||||
{
|
||||
std::cout << "Comparison" << std::endl;
|
||||
return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
|
||||
}
|
||||
int compare(boost::long_long_type i)const
|
||||
{
|
||||
std::cout << "Comparison with int" << std::endl;
|
||||
return m_value > i ? 1 : (m_value < i ? -1 : 0);
|
||||
}
|
||||
int compare(boost::ulong_long_type i)const
|
||||
{
|
||||
std::cout << "Comparison with unsigned" << std::endl;
|
||||
return m_value > i ? 1 : (m_value < i ? -1 : 0);
|
||||
}
|
||||
int compare(long double d)const
|
||||
{
|
||||
std::cout << "Comparison with long double" << std::endl;
|
||||
return m_value > d ? 1 : (m_value < d ? -1 : 0);
|
||||
}
|
||||
long double m_value;
|
||||
};
|
||||
|
||||
inline void eval_add(number_backend_float_architype& result, const number_backend_float_architype& o)
|
||||
{
|
||||
std::cout << "Addition (" << result.m_value << " += " << o.m_value << ")" << std::endl;
|
||||
result.m_value += o.m_value;
|
||||
}
|
||||
inline void eval_subtract(number_backend_float_architype& result, const number_backend_float_architype& o)
|
||||
{
|
||||
std::cout << "Subtraction (" << result.m_value << " -= " << o.m_value << ")" << std::endl;
|
||||
result.m_value -= o.m_value;
|
||||
}
|
||||
inline void eval_multiply(number_backend_float_architype& result, const number_backend_float_architype& o)
|
||||
{
|
||||
std::cout << "Multiplication (" << result.m_value << " *= " << o.m_value << ")" << std::endl;
|
||||
result.m_value *= o.m_value;
|
||||
}
|
||||
inline void eval_divide(number_backend_float_architype& result, const number_backend_float_architype& o)
|
||||
{
|
||||
std::cout << "Division (" << result.m_value << " /= " << o.m_value << ")" << std::endl;
|
||||
result.m_value /= o.m_value;
|
||||
}
|
||||
|
||||
inline void eval_convert_to(boost::ulong_long_type* result, const number_backend_float_architype& val)
|
||||
{
|
||||
*result = static_cast<boost::ulong_long_type>(val.m_value);
|
||||
}
|
||||
inline void eval_convert_to(boost::long_long_type* result, const number_backend_float_architype& val)
|
||||
{
|
||||
*result = static_cast<boost::long_long_type>(val.m_value);
|
||||
}
|
||||
inline void eval_convert_to(long double* result, number_backend_float_architype& val)
|
||||
{
|
||||
*result = val.m_value;
|
||||
}
|
||||
|
||||
inline void eval_frexp(number_backend_float_architype& result, const number_backend_float_architype& arg, int* exp)
|
||||
{
|
||||
result = std::frexp(arg.m_value, exp);
|
||||
}
|
||||
|
||||
inline void eval_ldexp(number_backend_float_architype& result, const number_backend_float_architype& arg, int exp)
|
||||
{
|
||||
result = std::ldexp(arg.m_value, exp);
|
||||
}
|
||||
|
||||
inline void eval_floor(number_backend_float_architype& result, const number_backend_float_architype& arg)
|
||||
{
|
||||
result = std::floor(arg.m_value);
|
||||
}
|
||||
|
||||
inline void eval_ceil(number_backend_float_architype& result, const number_backend_float_architype& arg)
|
||||
{
|
||||
result = std::ceil(arg.m_value);
|
||||
}
|
||||
|
||||
inline void eval_sqrt(number_backend_float_architype& result, const number_backend_float_architype& arg)
|
||||
{
|
||||
result = std::sqrt(arg.m_value);
|
||||
}
|
||||
|
||||
inline int eval_fpclassify(const number_backend_float_architype& arg)
|
||||
{
|
||||
return (boost::math::fpclassify)(arg.m_value);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(const number_backend_float_architype& v)
|
||||
{
|
||||
boost::hash<long double> hasher;
|
||||
return hasher(v.m_value);
|
||||
}
|
||||
|
||||
typedef boost::multiprecision::number<number_backend_float_architype> mp_number_float_architype;
|
||||
|
||||
} // namespace
|
||||
|
||||
template<>
|
||||
struct number_category<concepts::number_backend_float_architype> : public mpl::int_<number_kind_floating_point>{};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace std{
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::concepts::number_backend_float_architype, ExpressionTemplates> > : public std::numeric_limits<long double>
|
||||
{
|
||||
typedef std::numeric_limits<long double> base_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::concepts::number_backend_float_architype, ExpressionTemplates> number_type;
|
||||
public:
|
||||
static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
|
||||
static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
|
||||
static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
|
||||
static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
|
||||
static number_type round_error() BOOST_NOEXCEPT { return base_type::round_error(); }
|
||||
static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
|
||||
static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
|
||||
static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
|
||||
static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,700 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_BIN_FLOAT_IO_HPP
|
||||
#define BOOST_MP_CPP_BIN_FLOAT_IO_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace cpp_bf_io_detail{
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Multiplies a by b and shifts the result so it fits inside max_bits bits,
|
||||
// returns by how much the result was shifted.
|
||||
//
|
||||
template <class I>
|
||||
inline I restricted_multiply(cpp_int& result, const cpp_int& a, const cpp_int& b, I max_bits, boost::int64_t& error)
|
||||
{
|
||||
result = a * b;
|
||||
I gb = msb(result);
|
||||
I rshift = 0;
|
||||
if(gb > max_bits)
|
||||
{
|
||||
rshift = gb - max_bits;
|
||||
I lb = lsb(result);
|
||||
int roundup = 0;
|
||||
// The error rate increases by the error of both a and b,
|
||||
// this may be overly pessimistic in many case as we're assuming
|
||||
// that a and b have the same level of uncertainty...
|
||||
if(lb < rshift)
|
||||
error = error ? error * 2 : 1;
|
||||
if(rshift)
|
||||
{
|
||||
BOOST_ASSERT(rshift < INT_MAX);
|
||||
if(bit_test(result, static_cast<unsigned>(rshift - 1)))
|
||||
{
|
||||
if(lb == rshift - 1)
|
||||
roundup = 1;
|
||||
else
|
||||
roundup = 2;
|
||||
}
|
||||
result >>= rshift;
|
||||
}
|
||||
if((roundup == 2) || ((roundup == 1) && (result.backend().limbs()[0] & 1)))
|
||||
++result;
|
||||
}
|
||||
return rshift;
|
||||
}
|
||||
//
|
||||
// Computes a^e shifted to the right so it fits in max_bits, returns how far
|
||||
// to the right we are shifted.
|
||||
//
|
||||
template <class I>
|
||||
inline I restricted_pow(cpp_int& result, const cpp_int& a, I e, I max_bits, boost::int64_t& error)
|
||||
{
|
||||
BOOST_ASSERT(&result != &a);
|
||||
I exp = 0;
|
||||
if(e == 1)
|
||||
{
|
||||
result = a;
|
||||
return exp;
|
||||
}
|
||||
else if(e == 2)
|
||||
{
|
||||
return restricted_multiply(result, a, a, max_bits, error);
|
||||
}
|
||||
else if(e == 3)
|
||||
{
|
||||
exp = restricted_multiply(result, a, a, max_bits, error);
|
||||
exp += restricted_multiply(result, result, a, max_bits, error);
|
||||
return exp;
|
||||
}
|
||||
I p = e / 2;
|
||||
exp = restricted_pow(result, a, p, max_bits, error);
|
||||
exp *= 2;
|
||||
exp += restricted_multiply(result, result, result, max_bits, error);
|
||||
if(e & 1)
|
||||
exp += restricted_multiply(result, result, a, max_bits, error);
|
||||
return exp;
|
||||
}
|
||||
|
||||
inline int get_round_mode(const cpp_int& what, boost::int64_t location, boost::int64_t error)
|
||||
{
|
||||
//
|
||||
// Can we round what at /location/, if the error in what is /error/ in
|
||||
// units of 0.5ulp. Return:
|
||||
//
|
||||
// -1: Can't round.
|
||||
// 0: leave as is.
|
||||
// 1: tie.
|
||||
// 2: round up.
|
||||
//
|
||||
BOOST_ASSERT(location >= 0);
|
||||
BOOST_ASSERT(location < INT_MAX);
|
||||
boost::int64_t error_radius = error & 1 ? (1 + error) / 2 : error / 2;
|
||||
if(error_radius && ((int)msb(error_radius) >= location))
|
||||
return -1;
|
||||
if(bit_test(what, static_cast<unsigned>(location)))
|
||||
{
|
||||
if((int)lsb(what) == location)
|
||||
return error ? -1 : 1; // Either a tie or can't round depending on whether we have any error
|
||||
if(!error)
|
||||
return 2; // no error, round up.
|
||||
cpp_int t = what - error_radius;
|
||||
if((int)lsb(t) >= location)
|
||||
return -1;
|
||||
return 2;
|
||||
}
|
||||
else if(error)
|
||||
{
|
||||
cpp_int t = what + error_radius;
|
||||
return bit_test(t, static_cast<unsigned>(location)) ? -1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int get_round_mode(cpp_int& r, cpp_int& d, boost::int64_t error, const cpp_int& q)
|
||||
{
|
||||
//
|
||||
// Lets suppose we have an inexact division by d+delta, where the true
|
||||
// value for the divisor is d, and with |delta| <= error/2, then
|
||||
// we have calculated q and r such that:
|
||||
//
|
||||
// n r
|
||||
// --- = q + -----------
|
||||
// d + error d + error
|
||||
//
|
||||
// Rearranging for n / d we get:
|
||||
//
|
||||
// n delta*q + r
|
||||
// --- = q + -------------
|
||||
// d d
|
||||
//
|
||||
// So rounding depends on whether 2r + error * q > d.
|
||||
//
|
||||
// We return:
|
||||
// 0 = down down.
|
||||
// 1 = tie.
|
||||
// 2 = round up.
|
||||
// -1 = couldn't decide.
|
||||
//
|
||||
r <<= 1;
|
||||
int c = r.compare(d);
|
||||
if(c == 0)
|
||||
return error ? -1 : 1;
|
||||
if(c > 0)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
r -= error * q;
|
||||
return r.compare(d) > 0 ? 2 : -1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if(error)
|
||||
{
|
||||
r += error * q;
|
||||
return r.compare(d) < 0 ? 0 : -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace backends{
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
|
||||
cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::operator=(const char *s)
|
||||
{
|
||||
cpp_int n;
|
||||
boost::intmax_t decimal_exp = 0;
|
||||
boost::intmax_t digits_seen = 0;
|
||||
static const boost::intmax_t max_digits_seen = 4 + (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count * 301L) / 1000;
|
||||
bool ss = false;
|
||||
//
|
||||
// Extract the sign:
|
||||
//
|
||||
if(*s == '-')
|
||||
{
|
||||
ss = true;
|
||||
++s;
|
||||
}
|
||||
else if(*s == '+')
|
||||
++s;
|
||||
//
|
||||
// Special cases first:
|
||||
//
|
||||
if((std::strcmp(s, "nan") == 0) || (std::strcmp(s, "NaN") == 0) || (std::strcmp(s, "NAN") == 0))
|
||||
{
|
||||
return *this = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
|
||||
}
|
||||
if((std::strcmp(s, "inf") == 0) || (std::strcmp(s, "Inf") == 0) || (std::strcmp(s, "INF") == 0) || (std::strcmp(s, "infinity") == 0) || (std::strcmp(s, "Infinity") == 0) || (std::strcmp(s, "INFINITY") == 0))
|
||||
{
|
||||
*this = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
|
||||
if(ss)
|
||||
negate();
|
||||
return *this;
|
||||
}
|
||||
//
|
||||
// Digits before the point:
|
||||
//
|
||||
while(*s && (*s >= '0') && (*s <= '9'))
|
||||
{
|
||||
n *= 10u;
|
||||
n += *s - '0';
|
||||
if(digits_seen || (*s != '0'))
|
||||
++digits_seen;
|
||||
++s;
|
||||
}
|
||||
// The decimal point (we really should localise this!!)
|
||||
if(*s && (*s == '.'))
|
||||
++s;
|
||||
//
|
||||
// Digits after the point:
|
||||
//
|
||||
while(*s && (*s >= '0') && (*s <= '9'))
|
||||
{
|
||||
n *= 10u;
|
||||
n += *s - '0';
|
||||
--decimal_exp;
|
||||
if(digits_seen || (*s != '0'))
|
||||
++digits_seen;
|
||||
++s;
|
||||
if(digits_seen > max_digits_seen)
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Digits we're skipping:
|
||||
//
|
||||
while(*s && (*s >= '0') && (*s <= '9'))
|
||||
++s;
|
||||
//
|
||||
// See if there's an exponent:
|
||||
//
|
||||
if(*s && ((*s == 'e') || (*s == 'E')))
|
||||
{
|
||||
++s;
|
||||
boost::intmax_t e = 0;
|
||||
bool es = false;
|
||||
if(*s && (*s == '-'))
|
||||
{
|
||||
es = true;
|
||||
++s;
|
||||
}
|
||||
else if(*s && (*s == '+'))
|
||||
++s;
|
||||
while(*s && (*s >= '0') && (*s <= '9'))
|
||||
{
|
||||
e *= 10u;
|
||||
e += *s - '0';
|
||||
++s;
|
||||
}
|
||||
if(es)
|
||||
e = -e;
|
||||
decimal_exp += e;
|
||||
}
|
||||
if(*s)
|
||||
{
|
||||
//
|
||||
// Oops unexpected input at the end of the number:
|
||||
//
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unable to parse string as a valid floating point number."));
|
||||
}
|
||||
if(n == 0)
|
||||
{
|
||||
// Result is necessarily zero:
|
||||
*this = static_cast<limb_type>(0u);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
//
|
||||
// Set our working precision - this is heuristic based, we want
|
||||
// a value as small as possible > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count to avoid large computations
|
||||
// and excessive memory usage, but we also want to avoid having to
|
||||
// up the computation and start again at a higher precision.
|
||||
// So we round cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count up to the nearest whole number of limbs, and add
|
||||
// one limb for good measure. This works very well for small exponents,
|
||||
// but for larger exponents we may may need to restart, we could add some
|
||||
// extra precision right from the start for larger exponents, but this
|
||||
// seems to be slightly slower in the *average* case:
|
||||
//
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
boost::intmax_t max_bits = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 32;
|
||||
#else
|
||||
boost::intmax_t max_bits = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + ((cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count % limb_bits) ? (limb_bits - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count % limb_bits) : 0) + limb_bits;
|
||||
#endif
|
||||
boost::int64_t error = 0;
|
||||
boost::intmax_t calc_exp = 0;
|
||||
boost::intmax_t final_exponent = 0;
|
||||
|
||||
if(decimal_exp >= 0)
|
||||
{
|
||||
// Nice and simple, the result is an integer...
|
||||
do
|
||||
{
|
||||
cpp_int t;
|
||||
if(decimal_exp)
|
||||
{
|
||||
calc_exp = boost::multiprecision::cpp_bf_io_detail::restricted_pow(t, cpp_int(5), decimal_exp, max_bits, error);
|
||||
calc_exp += boost::multiprecision::cpp_bf_io_detail::restricted_multiply(t, t, n, max_bits, error);
|
||||
}
|
||||
else
|
||||
t = n;
|
||||
final_exponent = (boost::int64_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 + decimal_exp + calc_exp;
|
||||
int rshift = msb(t) - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1;
|
||||
if(rshift > 0)
|
||||
{
|
||||
final_exponent += rshift;
|
||||
int roundup = boost::multiprecision::cpp_bf_io_detail::get_round_mode(t, rshift - 1, error);
|
||||
t >>= rshift;
|
||||
if((roundup == 2) || ((roundup == 1) && t.backend().limbs()[0] & 1))
|
||||
++t;
|
||||
else if(roundup < 0)
|
||||
{
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
max_bits += 32;
|
||||
#else
|
||||
max_bits *= 2;
|
||||
#endif
|
||||
error = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(!error);
|
||||
}
|
||||
if(final_exponent > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
|
||||
{
|
||||
exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
|
||||
final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
|
||||
}
|
||||
else if(final_exponent < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
|
||||
{
|
||||
// Underflow:
|
||||
exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
|
||||
final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent() = static_cast<Exponent>(final_exponent);
|
||||
final_exponent = 0;
|
||||
}
|
||||
copy_and_round(*this, t.backend());
|
||||
break;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(ss != sign())
|
||||
negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Result is the ratio of two integers: we need to organise the
|
||||
// division so as to produce at least an N-bit result which we can
|
||||
// round according to the remainder.
|
||||
//cpp_int d = pow(cpp_int(5), -decimal_exp);
|
||||
do
|
||||
{
|
||||
cpp_int d;
|
||||
calc_exp = boost::multiprecision::cpp_bf_io_detail::restricted_pow(d, cpp_int(5), -decimal_exp, max_bits, error);
|
||||
int shift = (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - msb(n) + msb(d);
|
||||
final_exponent = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 + decimal_exp - calc_exp;
|
||||
if(shift > 0)
|
||||
{
|
||||
n <<= shift;
|
||||
final_exponent -= static_cast<Exponent>(shift);
|
||||
}
|
||||
cpp_int q, r;
|
||||
divide_qr(n, d, q, r);
|
||||
int gb = msb(q);
|
||||
BOOST_ASSERT((gb >= static_cast<int>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - 1));
|
||||
//
|
||||
// Check for rounding conditions we have to
|
||||
// handle ourselves:
|
||||
//
|
||||
int roundup = 0;
|
||||
if(gb == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1)
|
||||
{
|
||||
// Exactly the right number of bits, use the remainder to round:
|
||||
roundup = boost::multiprecision::cpp_bf_io_detail::get_round_mode(r, d, error, q);
|
||||
}
|
||||
else if(bit_test(q, gb - (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) && ((int)lsb(q) == (gb - (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count)))
|
||||
{
|
||||
// Too many bits in q and the bits in q indicate a tie, but we can break that using r,
|
||||
// note that the radius of error in r is error/2 * q:
|
||||
int lshift = gb - (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1;
|
||||
q >>= lshift;
|
||||
final_exponent += static_cast<Exponent>(lshift);
|
||||
BOOST_ASSERT((msb(q) >= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1));
|
||||
if(error && (r < (error / 2) * q))
|
||||
roundup = -1;
|
||||
else if(error && (r + (error / 2) * q >= d))
|
||||
roundup = -1;
|
||||
else
|
||||
roundup = r ? 2 : 1;
|
||||
}
|
||||
else if(error && (((error / 2) * q + r >= d) || (r < (error / 2) * q)))
|
||||
{
|
||||
// We might have been rounding up, or got the wrong quotient: can't tell!
|
||||
roundup = -1;
|
||||
}
|
||||
if(roundup < 0)
|
||||
{
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
max_bits += 32;
|
||||
#else
|
||||
max_bits *= 2;
|
||||
#endif
|
||||
error = 0;
|
||||
if(shift > 0)
|
||||
{
|
||||
n >>= shift;
|
||||
final_exponent += static_cast<Exponent>(shift);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if((roundup == 2) || ((roundup == 1) && q.backend().limbs()[0] & 1))
|
||||
++q;
|
||||
if(final_exponent > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
|
||||
{
|
||||
// Overflow:
|
||||
exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
|
||||
final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
|
||||
}
|
||||
else if(final_exponent < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
|
||||
{
|
||||
// Underflow:
|
||||
exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
|
||||
final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent() = static_cast<Exponent>(final_exponent);
|
||||
final_exponent = 0;
|
||||
}
|
||||
copy_and_round(*this, q.backend());
|
||||
if(ss != sign())
|
||||
negate();
|
||||
break;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
//
|
||||
// Check for scaling and/or over/under-flow:
|
||||
//
|
||||
final_exponent += exponent();
|
||||
if(final_exponent > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
|
||||
{
|
||||
// Overflow:
|
||||
exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
|
||||
bits() = limb_type(0);
|
||||
}
|
||||
else if(final_exponent < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
|
||||
{
|
||||
// Underflow:
|
||||
exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
|
||||
bits() = limb_type(0);
|
||||
sign() = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent() = static_cast<Exponent>(final_exponent);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
|
||||
std::string cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::str(std::streamsize dig, std::ios_base::fmtflags f) const
|
||||
{
|
||||
if(dig == 0)
|
||||
dig = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::max_digits10;
|
||||
|
||||
bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
|
||||
bool fixed = !scientific && (f & std::ios_base::fixed);
|
||||
|
||||
std::string s;
|
||||
|
||||
if(exponent() <= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
|
||||
{
|
||||
// How far to left-shift in order to demormalise the mantissa:
|
||||
boost::intmax_t shift = (boost::intmax_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - (boost::intmax_t)exponent() - 1;
|
||||
boost::intmax_t digits_wanted = static_cast<int>(dig);
|
||||
boost::intmax_t base10_exp = exponent() >= 0 ? static_cast<boost::intmax_t>(std::floor(0.30103 * exponent())) : static_cast<boost::intmax_t>(std::ceil(0.30103 * exponent()));
|
||||
//
|
||||
// For fixed formatting we want /dig/ digits after the decimal point,
|
||||
// so if the exponent is zero, allowing for the one digit before the
|
||||
// decimal point, we want 1 + dig digits etc.
|
||||
//
|
||||
if(fixed)
|
||||
digits_wanted += 1 + base10_exp;
|
||||
if(scientific)
|
||||
digits_wanted += 1;
|
||||
if(digits_wanted < -1)
|
||||
{
|
||||
// Fixed precision, no significant digits, and nothing to round!
|
||||
s = "0";
|
||||
if(sign())
|
||||
s.insert(static_cast<std::string::size_type>(0), 1, '-');
|
||||
boost::multiprecision::detail::format_float_string(s, base10_exp, dig, f, true);
|
||||
return s;
|
||||
}
|
||||
//
|
||||
// power10 is the base10 exponent we need to multiply/divide by in order
|
||||
// to convert our denormalised number to an integer with the right number of digits:
|
||||
//
|
||||
boost::intmax_t power10 = digits_wanted - base10_exp - 1;
|
||||
//
|
||||
// If we calculate 5^power10 rather than 10^power10 we need to move
|
||||
// 2^power10 into /shift/
|
||||
//
|
||||
shift -= power10;
|
||||
cpp_int i;
|
||||
int roundup = 0; // 0=no rounding, 1=tie, 2=up
|
||||
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
//
|
||||
// Set our working precision - this is heuristic based, we want
|
||||
// a value as small as possible > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count to avoid large computations
|
||||
// and excessive memory usage, but we also want to avoid having to
|
||||
// up the computation and start again at a higher precision.
|
||||
// So we round cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count up to the nearest whole number of limbs, and add
|
||||
// one limb for good measure. This works very well for small exponents,
|
||||
// but for larger exponents we add a few extra limbs to max_bits:
|
||||
//
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
boost::intmax_t max_bits = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 32;
|
||||
#else
|
||||
boost::intmax_t max_bits = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + ((cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count % limb_bits) ? (limb_bits - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count % limb_bits) : 0) + limb_bits;
|
||||
if(power10)
|
||||
max_bits += (msb(boost::multiprecision::detail::abs(power10)) / 8) * limb_bits;
|
||||
#endif
|
||||
do
|
||||
{
|
||||
boost::int64_t error = 0;
|
||||
boost::intmax_t calc_exp = 0;
|
||||
//
|
||||
// Our integer result is: bits() * 2^-shift * 5^power10
|
||||
//
|
||||
i = bits();
|
||||
if(shift < 0)
|
||||
{
|
||||
if(power10 >= 0)
|
||||
{
|
||||
// We go straight to the answer with all integer arithmetic,
|
||||
// the result is always exact and never needs rounding:
|
||||
BOOST_ASSERT(power10 <= (boost::intmax_t)INT_MAX);
|
||||
i <<= -shift;
|
||||
if(power10)
|
||||
i *= pow(cpp_int(5), static_cast<unsigned>(power10));
|
||||
}
|
||||
else if(power10 < 0)
|
||||
{
|
||||
cpp_int d;
|
||||
calc_exp = boost::multiprecision::cpp_bf_io_detail::restricted_pow(d, cpp_int(5), -power10, max_bits, error);
|
||||
shift += calc_exp;
|
||||
BOOST_ASSERT(shift < 0); // Must still be true!
|
||||
i <<= -shift;
|
||||
cpp_int r;
|
||||
divide_qr(i, d, i, r);
|
||||
roundup = boost::multiprecision::cpp_bf_io_detail::get_round_mode(r, d, error, i);
|
||||
if(roundup < 0)
|
||||
{
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
max_bits += 32;
|
||||
#else
|
||||
max_bits *= 2;
|
||||
#endif
|
||||
shift = (boost::intmax_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - exponent() - 1 - power10;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Our integer is bits() * 2^-shift * 10^power10
|
||||
//
|
||||
if(power10 > 0)
|
||||
{
|
||||
if(power10)
|
||||
{
|
||||
cpp_int t;
|
||||
calc_exp = boost::multiprecision::cpp_bf_io_detail::restricted_pow(t, cpp_int(5), power10, max_bits, error);
|
||||
calc_exp += boost::multiprecision::cpp_bf_io_detail::restricted_multiply(i, i, t, max_bits, error);
|
||||
shift -= calc_exp;
|
||||
}
|
||||
if((shift < 0) || ((shift == 0) && error))
|
||||
{
|
||||
// We only get here if we were asked for a crazy number of decimal digits -
|
||||
// more than are present in a 2^max_bits number.
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
max_bits += 32;
|
||||
#else
|
||||
max_bits *= 2;
|
||||
#endif
|
||||
shift = (boost::intmax_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - exponent() - 1 - power10;
|
||||
continue;
|
||||
}
|
||||
if(shift)
|
||||
{
|
||||
roundup = boost::multiprecision::cpp_bf_io_detail::get_round_mode(i, shift - 1, error);
|
||||
if(roundup < 0)
|
||||
{
|
||||
#ifdef BOOST_MP_STRESS_IO
|
||||
max_bits += 32;
|
||||
#else
|
||||
max_bits *= 2;
|
||||
#endif
|
||||
shift = (boost::intmax_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - exponent() - 1 - power10;
|
||||
continue;
|
||||
}
|
||||
i >>= shift;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're right shifting, *and* dividing by 5^-power10,
|
||||
// so 5^-power10 can never be that large or we'd simply
|
||||
// get zero as a result, and that case is already handled above:
|
||||
cpp_int r;
|
||||
BOOST_ASSERT(-power10 < INT_MAX);
|
||||
cpp_int d = pow(cpp_int(5), static_cast<unsigned>(-power10));
|
||||
d <<= shift;
|
||||
divide_qr(i, d, i, r);
|
||||
r <<= 1;
|
||||
int c = r.compare(d);
|
||||
roundup = c < 0 ? 0 : c == 0 ? 1 : 2;
|
||||
}
|
||||
}
|
||||
s = i.str(0, std::ios_base::fmtflags(0));
|
||||
//
|
||||
// Check if we got the right number of digits, this
|
||||
// is really a test of whether we calculated the
|
||||
// decimal exponent correctly:
|
||||
//
|
||||
boost::intmax_t digits_got = i ? static_cast<boost::intmax_t>(s.size()) : 0;
|
||||
if(digits_got != digits_wanted)
|
||||
{
|
||||
base10_exp += digits_got - digits_wanted;
|
||||
if(fixed)
|
||||
digits_wanted = digits_got; // strange but true.
|
||||
power10 = digits_wanted - base10_exp - 1;
|
||||
shift = (boost::intmax_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - exponent() - 1 - power10;
|
||||
if(fixed)
|
||||
break;
|
||||
roundup = 0;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while(true);
|
||||
//
|
||||
// Check whether we need to round up: note that we could equally round up
|
||||
// the integer /i/ above, but since we need to perform the rounding *after*
|
||||
// the conversion to a string and the digit count check, we might as well
|
||||
// do it here:
|
||||
//
|
||||
if((roundup == 2) || ((roundup == 1) && ((s[s.size() - 1] - '0') & 1)))
|
||||
{
|
||||
boost::multiprecision::detail::round_string_up_at(s, static_cast<int>(s.size() - 1), base10_exp);
|
||||
}
|
||||
|
||||
if(sign())
|
||||
s.insert(static_cast<std::string::size_type>(0), 1, '-');
|
||||
|
||||
boost::multiprecision::detail::format_float_string(s, base10_exp, dig, f, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(exponent())
|
||||
{
|
||||
case exponent_zero:
|
||||
s = sign() ? "-0" : f & std::ios_base::showpos ? "+0" : "0";
|
||||
boost::multiprecision::detail::format_float_string(s, 0, dig, f, true);
|
||||
break;
|
||||
case exponent_nan:
|
||||
s = "nan";
|
||||
break;
|
||||
case exponent_infinity:
|
||||
s = sign() ? "-inf" : f & std::ios_base::showpos ? "+inf" : "inf";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MULTIPRECISION_CPP_BIN_FLOAT_TRANSCENDENTAL_HPP
|
||||
#define BOOST_MULTIPRECISION_CPP_BIN_FLOAT_TRANSCENDENTAL_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
|
||||
void eval_exp_taylor(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
|
||||
{
|
||||
static const int bits = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count;
|
||||
//
|
||||
// Taylor series for small argument, note returns exp(x) - 1:
|
||||
//
|
||||
res = limb_type(0);
|
||||
cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> num(arg), denom, t;
|
||||
denom = limb_type(1);
|
||||
eval_add(res, num);
|
||||
|
||||
for(unsigned k = 2; ; ++k)
|
||||
{
|
||||
eval_multiply(denom, k);
|
||||
eval_multiply(num, arg);
|
||||
eval_divide(t, num, denom);
|
||||
eval_add(res, t);
|
||||
if(eval_is_zero(t) || (res.exponent() - bits > t.exponent()))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
|
||||
void eval_exp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
|
||||
{
|
||||
//
|
||||
// This is based on MPFR's method, let:
|
||||
//
|
||||
// n = floor(x / ln(2))
|
||||
//
|
||||
// Then:
|
||||
//
|
||||
// r = x - n ln(2) : 0 <= r < ln(2)
|
||||
//
|
||||
// We can reduce r further by dividing by 2^k, with k ~ sqrt(n),
|
||||
// so if:
|
||||
//
|
||||
// e0 = exp(r / 2^k) - 1
|
||||
//
|
||||
// With e0 evaluated by taylor series for small arguments, then:
|
||||
//
|
||||
// exp(x) = 2^n (1 + e0)^2^k
|
||||
//
|
||||
// Note that to preserve precision we actually square (1 + e0) k times, calculating
|
||||
// the result less one each time, i.e.
|
||||
//
|
||||
// (1 + e0)^2 - 1 = e0^2 + 2e0
|
||||
//
|
||||
// Then add the final 1 at the end, given that e0 is small, this effectively wipes
|
||||
// out the error in the last step.
|
||||
//
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_convert_to;
|
||||
|
||||
int type = eval_fpclassify(arg);
|
||||
bool isneg = eval_get_sign(arg) < 0;
|
||||
if(type == (int)FP_NAN)
|
||||
{
|
||||
res = arg;
|
||||
errno = EDOM;
|
||||
return;
|
||||
}
|
||||
else if(type == (int)FP_INFINITE)
|
||||
{
|
||||
res = arg;
|
||||
if(isneg)
|
||||
res = limb_type(0u);
|
||||
else
|
||||
res = arg;
|
||||
return;
|
||||
}
|
||||
else if(type == (int)FP_ZERO)
|
||||
{
|
||||
res = limb_type(1);
|
||||
return;
|
||||
}
|
||||
cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> t, n;
|
||||
if(isneg)
|
||||
{
|
||||
t = arg;
|
||||
t.negate();
|
||||
eval_exp(res, t);
|
||||
t.swap(res);
|
||||
res = limb_type(1);
|
||||
eval_divide(res, t);
|
||||
return;
|
||||
}
|
||||
|
||||
eval_divide(n, arg, default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >());
|
||||
eval_floor(n, n);
|
||||
eval_multiply(t, n, default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >());
|
||||
eval_subtract(t, arg);
|
||||
t.negate();
|
||||
if(eval_get_sign(t) < 0)
|
||||
{
|
||||
// There are some very rare cases where arg/ln2 is an integer, and the subsequent multiply
|
||||
// rounds up, in that situation t ends up negative at this point which breaks our invariants below:
|
||||
t = limb_type(0);
|
||||
}
|
||||
|
||||
Exponent k, nn;
|
||||
eval_convert_to(&nn, n);
|
||||
|
||||
if (nn == (std::numeric_limits<Exponent>::max)())
|
||||
{
|
||||
// The result will necessarily oveflow:
|
||||
res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(t.compare(default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >()) < 0);
|
||||
|
||||
k = nn ? Exponent(1) << (msb(nn) / 2) : 0;
|
||||
k = (std::min)(k, (Exponent)(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count / 4));
|
||||
eval_ldexp(t, t, -k);
|
||||
|
||||
eval_exp_taylor(res, t);
|
||||
//
|
||||
// Square 1 + res k times:
|
||||
//
|
||||
for(Exponent s = 0; s < k; ++s)
|
||||
{
|
||||
t.swap(res);
|
||||
eval_multiply(res, t, t);
|
||||
eval_ldexp(t, t, 1);
|
||||
eval_add(res, t);
|
||||
}
|
||||
eval_add(res, limb_type(1));
|
||||
eval_ldexp(res, res, nn);
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2018 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_MP_CPP_COMPLEX_HPP
|
||||
#define BOOST_MP_CPP_COMPLEX_HPP
|
||||
|
||||
#include <boost/multiprecision/cpp_bin_float.hpp>
|
||||
#include <boost/multiprecision/complex_adaptor.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
|
||||
#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES
|
||||
|
||||
template <unsigned Digits, backends::digit_base_type DigitBase = backends::digit_base_10, class Allocator = void, class Exponent = int, Exponent MinExponent = 0, Exponent MaxExponent = 0>
|
||||
using cpp_complex_backend = complex_adaptor<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> >;
|
||||
|
||||
template <unsigned Digits, backends::digit_base_type DigitBase = digit_base_10, class Allocator = void, class Exponent = int, Exponent MinExponent = 0, Exponent MaxExponent = 0, expression_template_option ExpressionTemplates = et_off>
|
||||
using cpp_complex = number<complex_adaptor<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> >, ExpressionTemplates>;
|
||||
|
||||
typedef cpp_complex<50> cpp_complex_50;
|
||||
typedef cpp_complex<100> cpp_complex_100;
|
||||
|
||||
typedef cpp_complex<24, backends::digit_base_2, void, boost::int16_t, -126, 127> cpp_complex_single;
|
||||
typedef cpp_complex<53, backends::digit_base_2, void, boost::int16_t, -1022, 1023> cpp_complex_double;
|
||||
typedef cpp_complex<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383> cpp_complex_extended;
|
||||
typedef cpp_complex<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383> cpp_complex_quad;
|
||||
|
||||
#else
|
||||
|
||||
typedef number<complex_adaptor<cpp_bin_float<50> >, et_off> cpp_complex_50;
|
||||
typedef number<complex_adaptor<cpp_bin_float<100> >, et_off> cpp_complex_100;
|
||||
|
||||
typedef number<complex_adaptor<cpp_bin_float<24, backends::digit_base_2, void, boost::int16_t, -126, 127> >, et_off> cpp_complex_single;
|
||||
typedef number<complex_adaptor<cpp_bin_float<53, backends::digit_base_2, void, boost::int16_t, -1022, 1023> >, et_off> cpp_complex_double;
|
||||
typedef number<complex_adaptor<cpp_bin_float<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383> >, et_off> cpp_complex_extended;
|
||||
typedef number<complex_adaptor<cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383> >, et_off> cpp_complex_quad;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,554 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_ADD_HPP
|
||||
#define BOOST_MP_CPP_INT_ADD_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
//
|
||||
// This is the key addition routine where all the argument types are non-trivial cpp_int's:
|
||||
//
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
double_limb_type carry = 0;
|
||||
unsigned m, x;
|
||||
unsigned as = a.size();
|
||||
unsigned bs = b.size();
|
||||
minmax(as, bs, m, x);
|
||||
if(x == 1)
|
||||
{
|
||||
bool s = a.sign();
|
||||
result = static_cast<double_limb_type>(*a.limbs()) + static_cast<double_limb_type>(*b.limbs());
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
result.resize(x, x);
|
||||
typename CppInt2::const_limb_pointer pa = a.limbs();
|
||||
typename CppInt3::const_limb_pointer pb = b.limbs();
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
typename CppInt1::limb_pointer pr_end = pr + m;
|
||||
|
||||
if(as < bs)
|
||||
swap(pa, pb);
|
||||
|
||||
// First where a and b overlap:
|
||||
while(pr != pr_end)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
*pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
*pr = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= CppInt1::limb_bits;
|
||||
++pr, ++pa, ++pb;
|
||||
}
|
||||
pr_end += x - m;
|
||||
// Now where only a has digits:
|
||||
while(pr != pr_end)
|
||||
{
|
||||
if(!carry)
|
||||
{
|
||||
if(pa != pr)
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
std::copy(pa, pa + (pr_end - pr), stdext::checked_array_iterator<limb_type*>(pr, result.size()));
|
||||
#else
|
||||
std::copy(pa, pa + (pr_end - pr), pr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
carry += static_cast<double_limb_type>(*pa);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
*pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
*pr = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= CppInt1::limb_bits;
|
||||
++pr, ++pa;
|
||||
}
|
||||
if(carry)
|
||||
{
|
||||
// We overflowed, need to add one more limb:
|
||||
result.resize(x + 1, x + 1);
|
||||
if(result.size() > x)
|
||||
result.limbs()[x] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
}
|
||||
//
|
||||
// As above, but for adding a single limb to a non-trivial cpp_int:
|
||||
//
|
||||
template <class CppInt1, class CppInt2>
|
||||
inline void add_unsigned(CppInt1& result, const CppInt2& a, const limb_type& o) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
// Addition using modular arithmetic.
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
if(&result != &a)
|
||||
result.resize(a.size(), a.size());
|
||||
double_limb_type carry = o;
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
typename CppInt2::const_limb_pointer pa = a.limbs();
|
||||
unsigned i = 0;
|
||||
// Addition with carry until we either run out of digits or carry is zero:
|
||||
for(; carry && (i < result.size()); ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(pa[i]);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[i] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
pr[i] = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
// Just copy any remaining digits:
|
||||
if(&a != &result)
|
||||
{
|
||||
for(; i < result.size(); ++i)
|
||||
pr[i] = pa[i];
|
||||
}
|
||||
if(carry)
|
||||
{
|
||||
// We overflowed, need to add one more limb:
|
||||
unsigned x = result.size();
|
||||
result.resize(x + 1, x + 1);
|
||||
if(result.size() > x)
|
||||
result.limbs()[x] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
}
|
||||
//
|
||||
// Core subtraction routine for all non-trivial cpp_int's:
|
||||
//
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
double_limb_type borrow = 0;
|
||||
unsigned m, x;
|
||||
minmax(a.size(), b.size(), m, x);
|
||||
//
|
||||
// special cases for small limb counts:
|
||||
//
|
||||
if(x == 1)
|
||||
{
|
||||
bool s = a.sign();
|
||||
limb_type al = *a.limbs();
|
||||
limb_type bl = *b.limbs();
|
||||
if(bl > al)
|
||||
{
|
||||
std::swap(al, bl);
|
||||
s = !s;
|
||||
}
|
||||
result = al - bl;
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
// This isn't used till later, but comparison has to occur before we resize the result,
|
||||
// as that may also resize a or b if this is an inplace operation:
|
||||
int c = a.compare_unsigned(b);
|
||||
// Set up the result vector:
|
||||
result.resize(x, x);
|
||||
// Now that a, b, and result are stable, get pointers to their limbs:
|
||||
typename CppInt2::const_limb_pointer pa = a.limbs();
|
||||
typename CppInt3::const_limb_pointer pb = b.limbs();
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
bool swapped = false;
|
||||
if(c < 0)
|
||||
{
|
||||
swap(pa, pb);
|
||||
swapped = true;
|
||||
}
|
||||
else if(c == 0)
|
||||
{
|
||||
result = static_cast<limb_type>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned i = 0;
|
||||
// First where a and b overlap:
|
||||
while(i < m)
|
||||
{
|
||||
borrow = static_cast<double_limb_type>(pa[i]) - static_cast<double_limb_type>(pb[i]) - borrow;
|
||||
pr[i] = static_cast<limb_type>(borrow);
|
||||
borrow = (borrow >> CppInt1::limb_bits) & 1u;
|
||||
++i;
|
||||
}
|
||||
// Now where only a has digits, only as long as we've borrowed:
|
||||
while(borrow && (i < x))
|
||||
{
|
||||
borrow = static_cast<double_limb_type>(pa[i]) - borrow;
|
||||
pr[i] = static_cast<limb_type>(borrow);
|
||||
borrow = (borrow >> CppInt1::limb_bits) & 1u;
|
||||
++i;
|
||||
}
|
||||
// Any remaining digits are the same as those in pa:
|
||||
if((x != i) && (pa != pr))
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
std::copy(pa + i, pa + x, stdext::checked_array_iterator<limb_type*>(pr + i, result.size() - i));
|
||||
#else
|
||||
std::copy(pa + i, pa + x, pr + i);
|
||||
#endif
|
||||
BOOST_ASSERT(0 == borrow);
|
||||
|
||||
//
|
||||
// We may have lost digits, if so update limb usage count:
|
||||
//
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
if(swapped)
|
||||
result.negate();
|
||||
}
|
||||
//
|
||||
// And again to subtract a single limb:
|
||||
//
|
||||
template <class CppInt1, class CppInt2>
|
||||
inline void subtract_unsigned(CppInt1& result, const CppInt2& a, const limb_type& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
// Subtract one limb.
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
BOOST_STATIC_CONSTANT(double_limb_type, borrow = static_cast<double_limb_type>(CppInt1::max_limb_value) + 1);
|
||||
result.resize(a.size(), a.size());
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
typename CppInt2::const_limb_pointer pa = a.limbs();
|
||||
if(*pa >= b)
|
||||
{
|
||||
*pr = *pa - b;
|
||||
if(&result != &a)
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
std::copy(pa + 1, pa + a.size(), stdext::checked_array_iterator<limb_type*>(pr + 1, result.size() - 1));
|
||||
#else
|
||||
std::copy(pa + 1, pa + a.size(), pr + 1);
|
||||
#endif
|
||||
result.sign(a.sign());
|
||||
}
|
||||
else if((result.size() == 1) && (*pr == 0))
|
||||
{
|
||||
result.sign(false); // zero is unsigned.
|
||||
}
|
||||
}
|
||||
else if(result.size() == 1)
|
||||
{
|
||||
*pr = b - *pa;
|
||||
result.sign(!a.sign());
|
||||
}
|
||||
else
|
||||
{
|
||||
*pr = static_cast<limb_type>((borrow + *pa) - b);
|
||||
unsigned i = 1;
|
||||
while(!pa[i])
|
||||
{
|
||||
pr[i] = CppInt1::max_limb_value;
|
||||
++i;
|
||||
}
|
||||
pr[i] = pa[i] - 1;
|
||||
if(&result != &a)
|
||||
{
|
||||
++i;
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
std::copy(pa + i, pa + a.size(), stdext::checked_array_iterator<limb_type*>(pr + i, result.size() - i));
|
||||
#else
|
||||
std::copy(pa + i, pa + a.size(), pr + i);
|
||||
#endif
|
||||
}
|
||||
result.normalize();
|
||||
result.sign(a.sign());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Now the actual functions called by the front end, all of which forward to one of the above:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_add(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_add(result, result, o);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
|
||||
eval_add(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(a.sign() != b.sign())
|
||||
{
|
||||
subtract_unsigned(result, a, b);
|
||||
return;
|
||||
}
|
||||
add_unsigned(result, a, b);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(result.sign())
|
||||
{
|
||||
subtract_unsigned(result, result, o);
|
||||
}
|
||||
else
|
||||
add_unsigned(result, result, o);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_add(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(a.sign())
|
||||
{
|
||||
subtract_unsigned(result, a, o);
|
||||
}
|
||||
else
|
||||
add_unsigned(result, a, o);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_add(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(o < 0)
|
||||
eval_subtract(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
|
||||
else if(o > 0)
|
||||
eval_add(result, static_cast<limb_type>(o));
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_add(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(o < 0)
|
||||
eval_subtract(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
|
||||
else if(o > 0)
|
||||
eval_add(result, a, static_cast<limb_type>(o));
|
||||
else if(&result != &a)
|
||||
result = a;
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(result.sign())
|
||||
{
|
||||
add_unsigned(result, result, o);
|
||||
}
|
||||
else
|
||||
subtract_unsigned(result, result, o);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(a.sign())
|
||||
{
|
||||
add_unsigned(result, a, o);
|
||||
}
|
||||
else
|
||||
{
|
||||
subtract_unsigned(result, a, o);
|
||||
}
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(o)
|
||||
{
|
||||
if(o < 0)
|
||||
eval_add(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
|
||||
else
|
||||
eval_subtract(result, static_cast<limb_type>(o));
|
||||
}
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(o)
|
||||
{
|
||||
if(o < 0)
|
||||
eval_add(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
|
||||
else
|
||||
eval_subtract(result, a, static_cast<limb_type>(o));
|
||||
}
|
||||
else if(&result != &a)
|
||||
result = a;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_increment(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
static const limb_type one = 1;
|
||||
if(!result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
|
||||
++result.limbs()[0];
|
||||
else if (result.sign() && result.limbs()[0])
|
||||
{
|
||||
--result.limbs()[0];
|
||||
if (!result.limbs()[0])
|
||||
result.sign(false);
|
||||
}
|
||||
else
|
||||
eval_add(result, one);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_decrement(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
static const limb_type one = 1;
|
||||
if(!result.sign() && result.limbs()[0])
|
||||
--result.limbs()[0];
|
||||
else if (result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
|
||||
++result.limbs()[0];
|
||||
else
|
||||
eval_subtract(result, one);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_subtract(result, result, o);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(a.sign() != b.sign())
|
||||
{
|
||||
add_unsigned(result, a, b);
|
||||
return;
|
||||
}
|
||||
subtract_unsigned(result, a, b);
|
||||
}
|
||||
|
||||
//
|
||||
// Simple addition and subtraction routine for trivial cpp_int's come last:
|
||||
//
|
||||
// One of the arguments is signed:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_add(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(result.sign() != o.sign())
|
||||
{
|
||||
if(*o.limbs() > *result.limbs())
|
||||
{
|
||||
*result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
*result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
}
|
||||
else
|
||||
*result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
// Simple version for two unsigned arguments:
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
// signed subtraction:
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(result.sign() != o.sign())
|
||||
{
|
||||
*result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
}
|
||||
else if(*result.limbs() < *o.limbs())
|
||||
{
|
||||
*result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
*result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_subtract(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,842 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_BIT_HPP
|
||||
#define BOOST_MP_CPP_INT_BIT_HPP
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4319)
|
||||
#endif
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
void is_valid_bitwise_op(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::int_<checked>&)
|
||||
{
|
||||
if(result.sign() || o.sign())
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
void is_valid_bitwise_op(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& , const mpl::int_<unchecked>&){}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
void is_valid_bitwise_op(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const mpl::int_<checked>&)
|
||||
{
|
||||
if(result.sign())
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
void is_valid_bitwise_op(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const mpl::int_<checked>&){}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
void is_valid_bitwise_op(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const mpl::int_<unchecked>&){}
|
||||
|
||||
template <class CppInt1, class CppInt2, class Op>
|
||||
void bitwise_op(
|
||||
CppInt1& result,
|
||||
const CppInt2& o,
|
||||
Op op, const mpl::true_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
|
||||
{
|
||||
//
|
||||
// There are 4 cases:
|
||||
// * Both positive.
|
||||
// * result negative, o positive.
|
||||
// * o negative, result positive.
|
||||
// * Both negative.
|
||||
//
|
||||
// When one arg is negative we convert to 2's complement form "on the fly",
|
||||
// and then convert back to signed-magnitude form at the end.
|
||||
//
|
||||
// Note however, that if the type is checked, then bitwise ops on negative values
|
||||
// are not permitted and an exception will result.
|
||||
//
|
||||
is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
|
||||
//
|
||||
// First figure out how big the result needs to be and set up some data:
|
||||
//
|
||||
unsigned rs = result.size();
|
||||
unsigned os = o.size();
|
||||
unsigned m, x;
|
||||
minmax(rs, os, m, x);
|
||||
result.resize(x, x);
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
typename CppInt2::const_limb_pointer po = o.limbs();
|
||||
for(unsigned i = rs; i < x; ++i)
|
||||
pr[i] = 0;
|
||||
|
||||
limb_type next_limb = 0;
|
||||
|
||||
if(!result.sign())
|
||||
{
|
||||
if(!o.sign())
|
||||
{
|
||||
for(unsigned i = 0; i < os; ++i)
|
||||
pr[i] = op(pr[i], po[i]);
|
||||
for(unsigned i = os; i < x; ++i)
|
||||
pr[i] = op(pr[i], limb_type(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// "o" is negative:
|
||||
double_limb_type carry = 1;
|
||||
for(unsigned i = 0; i < os; ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(~po[i]);
|
||||
pr[i] = op(pr[i], static_cast<limb_type>(carry));
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
for(unsigned i = os; i < x; ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(~limb_type(0));
|
||||
pr[i] = op(pr[i], static_cast<limb_type>(carry));
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
// Set the overflow into the "extra" limb:
|
||||
carry += static_cast<double_limb_type>(~limb_type(0));
|
||||
next_limb = op(limb_type(0), static_cast<limb_type>(carry));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!o.sign())
|
||||
{
|
||||
// "result" is negative:
|
||||
double_limb_type carry = 1;
|
||||
for(unsigned i = 0; i < os; ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(~pr[i]);
|
||||
pr[i] = op(static_cast<limb_type>(carry), po[i]);
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
for(unsigned i = os; i < x; ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(~pr[i]);
|
||||
pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
// Set the overflow into the "extra" limb:
|
||||
carry += static_cast<double_limb_type>(~limb_type(0));
|
||||
next_limb = op(static_cast<limb_type>(carry), limb_type(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// both are negative:
|
||||
double_limb_type r_carry = 1;
|
||||
double_limb_type o_carry = 1;
|
||||
for(unsigned i = 0; i < os; ++i)
|
||||
{
|
||||
r_carry += static_cast<double_limb_type>(~pr[i]);
|
||||
o_carry += static_cast<double_limb_type>(~po[i]);
|
||||
pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
|
||||
r_carry >>= CppInt1::limb_bits;
|
||||
o_carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
for(unsigned i = os; i < x; ++i)
|
||||
{
|
||||
r_carry += static_cast<double_limb_type>(~pr[i]);
|
||||
o_carry += static_cast<double_limb_type>(~limb_type(0));
|
||||
pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
|
||||
r_carry >>= CppInt1::limb_bits;
|
||||
o_carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
// Set the overflow into the "extra" limb:
|
||||
r_carry += static_cast<double_limb_type>(~limb_type(0));
|
||||
o_carry += static_cast<double_limb_type>(~limb_type(0));
|
||||
next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
|
||||
}
|
||||
}
|
||||
//
|
||||
// See if the result is negative or not:
|
||||
//
|
||||
if(static_cast<signed_limb_type>(next_limb) < 0)
|
||||
{
|
||||
double_limb_type carry = 1;
|
||||
for(unsigned i = 0; i < x; ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(~pr[i]);
|
||||
pr[i] = static_cast<limb_type>(carry);
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
if(carry)
|
||||
{
|
||||
result.resize(x + 1, x);
|
||||
if(result.size() > x)
|
||||
result.limbs()[x] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.sign(true);
|
||||
}
|
||||
else
|
||||
result.sign(false);
|
||||
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <class CppInt1, class CppInt2, class Op>
|
||||
void bitwise_op(
|
||||
CppInt1& result,
|
||||
const CppInt2& o,
|
||||
Op op, const mpl::false_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
|
||||
{
|
||||
//
|
||||
// Both arguments are unsigned types, very simple case handled as a special case.
|
||||
//
|
||||
// First figure out how big the result needs to be and set up some data:
|
||||
//
|
||||
unsigned rs = result.size();
|
||||
unsigned os = o.size();
|
||||
unsigned m, x;
|
||||
minmax(rs, os, m, x);
|
||||
result.resize(x, x);
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
typename CppInt2::const_limb_pointer po = o.limbs();
|
||||
for(unsigned i = rs; i < x; ++i)
|
||||
pr[i] = 0;
|
||||
|
||||
for(unsigned i = 0; i < os; ++i)
|
||||
pr[i] = op(pr[i], po[i]);
|
||||
for(unsigned i = os; i < x; ++i)
|
||||
pr[i] = op(pr[i], limb_type(0));
|
||||
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
struct bit_and{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a & b; } };
|
||||
struct bit_or { limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a | b; } };
|
||||
struct bit_xor{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a ^ b; } };
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_bitwise_and(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
bitwise_op(result, o, bit_and(),
|
||||
mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_bitwise_or(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
bitwise_op(result, o, bit_or(),
|
||||
mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_bitwise_xor(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
bitwise_op(result, o, bit_xor(),
|
||||
mpl::bool_<std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed>());
|
||||
}
|
||||
//
|
||||
// Again for operands which are single limbs:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
|
||||
eval_bitwise_and(
|
||||
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
|
||||
limb_type l) BOOST_NOEXCEPT
|
||||
{
|
||||
result.limbs()[0] &= l;
|
||||
result.resize(1, 1);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
|
||||
eval_bitwise_or(
|
||||
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
|
||||
limb_type l) BOOST_NOEXCEPT
|
||||
{
|
||||
result.limbs()[0] |= l;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
|
||||
eval_bitwise_xor(
|
||||
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
|
||||
limb_type l) BOOST_NOEXCEPT
|
||||
{
|
||||
result.limbs()[0] ^= l;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_complement(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
|
||||
// Increment and negate:
|
||||
result = o;
|
||||
eval_increment(result);
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
|
||||
eval_complement(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
unsigned os = o.size();
|
||||
result.resize(UINT_MAX, os);
|
||||
for(unsigned i = 0; i < os; ++i)
|
||||
result.limbs()[i] = ~o.limbs()[i];
|
||||
for(unsigned i = os; i < result.size(); ++i)
|
||||
result.limbs()[i] = ~static_cast<limb_type>(0);
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline void left_shift_byte(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
|
||||
unsigned ors = result.size();
|
||||
if((ors == 1) && (!*result.limbs()))
|
||||
return; // shifting zero yields zero.
|
||||
unsigned rs = ors;
|
||||
if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
|
||||
++rs; // Most significant limb will overflow when shifted
|
||||
rs += offset;
|
||||
result.resize(rs, rs);
|
||||
rs = result.size();
|
||||
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
|
||||
if(rs != ors)
|
||||
pr[rs - 1] = 0u;
|
||||
std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT);
|
||||
std::size_t len = (std::min)(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes);
|
||||
if(bytes >= rs * sizeof(limb_type))
|
||||
result = static_cast<limb_type>(0u);
|
||||
else
|
||||
{
|
||||
unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
|
||||
std::memmove(pc + bytes, pc, len);
|
||||
std::memset(pc, 0, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline void left_shift_limb(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
|
||||
|
||||
unsigned ors = result.size();
|
||||
if((ors == 1) && (!*result.limbs()))
|
||||
return; // shifting zero yields zero.
|
||||
unsigned rs = ors;
|
||||
if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
|
||||
++rs; // Most significant limb will overflow when shifted
|
||||
rs += offset;
|
||||
result.resize(rs, rs);
|
||||
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
|
||||
if(offset > rs)
|
||||
{
|
||||
// The result is shifted past the end of the result:
|
||||
result = static_cast<limb_type>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned i = rs - result.size();
|
||||
for(; i < ors; ++i)
|
||||
pr[rs - 1 - i] = pr[ors - 1 - i];
|
||||
for(; i < rs; ++i)
|
||||
pr[rs - 1 - i] = 0;
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline void left_shift_generic(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
|
||||
|
||||
unsigned ors = result.size();
|
||||
if((ors == 1) && (!*result.limbs()))
|
||||
return; // shifting zero yields zero.
|
||||
unsigned rs = ors;
|
||||
if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
|
||||
++rs; // Most significant limb will overflow when shifted
|
||||
rs += offset;
|
||||
result.resize(rs, rs);
|
||||
bool truncated = result.size() != rs;
|
||||
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
|
||||
if(offset > rs)
|
||||
{
|
||||
// The result is shifted past the end of the result:
|
||||
result = static_cast<limb_type>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned i = rs - result.size();
|
||||
// This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
|
||||
BOOST_ASSERT(shift);
|
||||
if(!truncated)
|
||||
{
|
||||
if(rs > ors + offset)
|
||||
{
|
||||
pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
|
||||
--rs;
|
||||
}
|
||||
else
|
||||
{
|
||||
pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
|
||||
if(ors > 1)
|
||||
pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for(; rs - i >= 2 + 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 >= 1 + offset)
|
||||
{
|
||||
pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
|
||||
++i;
|
||||
}
|
||||
for(; i < rs; ++i)
|
||||
pr[rs - 1 - i] = 0;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_left_shift(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
if(!s)
|
||||
return;
|
||||
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
|
||||
static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
|
||||
static const limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
if((s & limb_shift_mask) == 0)
|
||||
{
|
||||
left_shift_limb(result, s);
|
||||
}
|
||||
else if((s & byte_shift_mask) == 0)
|
||||
{
|
||||
left_shift_byte(result, s);
|
||||
}
|
||||
#elif defined(BOOST_LITTLE_ENDIAN)
|
||||
static const limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
if((s & byte_shift_mask) == 0)
|
||||
{
|
||||
left_shift_byte(result, s);
|
||||
}
|
||||
#else
|
||||
static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
|
||||
if((s & limb_shift_mask) == 0)
|
||||
{
|
||||
left_shift_limb(result, s);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
left_shift_generic(result, s);
|
||||
}
|
||||
//
|
||||
// We may have shifted off the end and have leading zeros:
|
||||
//
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline void right_shift_byte(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
limb_type shift;
|
||||
BOOST_ASSERT((s % CHAR_BIT) == 0);
|
||||
unsigned ors = result.size();
|
||||
unsigned rs = ors;
|
||||
if(offset >= rs)
|
||||
{
|
||||
result = limb_type(0);
|
||||
return;
|
||||
}
|
||||
rs -= offset;
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
|
||||
shift = static_cast<limb_type>(s / CHAR_BIT);
|
||||
std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift);
|
||||
shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT;
|
||||
if(shift < Int::limb_bits)
|
||||
{
|
||||
pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
|
||||
if(!pr[ors - offset - 1] && (rs > 1))
|
||||
--rs;
|
||||
}
|
||||
result.resize(rs, rs);
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline void right_shift_limb(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
BOOST_ASSERT((s % Int::limb_bits) == 0);
|
||||
unsigned ors = result.size();
|
||||
unsigned rs = ors;
|
||||
if(offset >= rs)
|
||||
{
|
||||
result = limb_type(0);
|
||||
return;
|
||||
}
|
||||
rs -= offset;
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
unsigned i = 0;
|
||||
for(; i < rs; ++i)
|
||||
pr[i] = pr[i + offset];
|
||||
result.resize(rs, rs);
|
||||
}
|
||||
|
||||
template <class Int>
|
||||
inline void right_shift_generic(Int& result, double_limb_type s)
|
||||
{
|
||||
limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
|
||||
limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
|
||||
unsigned ors = result.size();
|
||||
unsigned rs = ors;
|
||||
if(offset >= rs)
|
||||
{
|
||||
result = limb_type(0);
|
||||
return;
|
||||
}
|
||||
rs -= offset;
|
||||
typename Int::limb_pointer pr = result.limbs();
|
||||
if((pr[ors - 1] >> shift) == 0)
|
||||
{
|
||||
if(--rs == 0)
|
||||
{
|
||||
result = limb_type(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
unsigned i = 0;
|
||||
|
||||
// This code only works for non-zero shift, otherwise we invoke undefined behaviour!
|
||||
BOOST_ASSERT(shift);
|
||||
for(; i + offset + 1 < ors; ++i)
|
||||
{
|
||||
pr[i] = pr[i + offset] >> shift;
|
||||
pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
|
||||
}
|
||||
pr[i] = pr[i + offset] >> shift;
|
||||
result.resize(rs, rs);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
|
||||
eval_right_shift(
|
||||
cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
|
||||
double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
|
||||
if(!s)
|
||||
return;
|
||||
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
|
||||
static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
static const limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
if((s & limb_shift_mask) == 0)
|
||||
right_shift_limb(result, s);
|
||||
else if((s & byte_shift_mask) == 0)
|
||||
right_shift_byte(result, s);
|
||||
#elif defined(BOOST_LITTLE_ENDIAN)
|
||||
static const limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
if((s & byte_shift_mask) == 0)
|
||||
right_shift_byte(result, s);
|
||||
#else
|
||||
static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
if((s & limb_shift_mask) == 0)
|
||||
right_shift_limb(result, s);
|
||||
#endif
|
||||
else
|
||||
right_shift_generic(result, s);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type
|
||||
eval_right_shift(
|
||||
cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result,
|
||||
double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
|
||||
if(!s)
|
||||
return;
|
||||
|
||||
bool is_neg = result.sign();
|
||||
if(is_neg)
|
||||
eval_increment(result);
|
||||
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
|
||||
static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
static const limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
if((s & limb_shift_mask) == 0)
|
||||
right_shift_limb(result, s);
|
||||
else if((s & byte_shift_mask) == 0)
|
||||
right_shift_byte(result, s);
|
||||
#elif defined(BOOST_LITTLE_ENDIAN)
|
||||
static const limb_type byte_shift_mask = CHAR_BIT - 1;
|
||||
if((s & byte_shift_mask) == 0)
|
||||
right_shift_byte(result, s);
|
||||
#else
|
||||
static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
|
||||
if((s & limb_shift_mask) == 0)
|
||||
right_shift_limb(result, s);
|
||||
#endif
|
||||
else
|
||||
right_shift_generic(result, s);
|
||||
if(is_neg)
|
||||
eval_decrement(result);
|
||||
}
|
||||
|
||||
//
|
||||
// Over again for trivial cpp_int's:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
|
||||
eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
|
||||
eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
// Nothing to check here... just make sure we don't invoke undefined behavior:
|
||||
is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s);
|
||||
if(result.sign() && (*result.limbs() == 0))
|
||||
result = static_cast<signed_limb_type>(-1);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
|
||||
>::type
|
||||
eval_complement(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
|
||||
//
|
||||
// If we're not checked then emulate 2's complement behavior:
|
||||
//
|
||||
if(o.sign())
|
||||
{
|
||||
*result.limbs() = *o.limbs() - 1;
|
||||
result.sign(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
*result.limbs() = 1 + *o.limbs();
|
||||
result.sign(true);
|
||||
}
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
>::type
|
||||
eval_complement(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = ~*o.limbs();
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
>::type
|
||||
eval_bitwise_and(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() &= *o.limbs();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
|
||||
>::type
|
||||
eval_bitwise_and(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_increment;
|
||||
|
||||
if(result.sign() || o.sign())
|
||||
{
|
||||
static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
|
||||
cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
|
||||
cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
|
||||
eval_bitwise_and(t1, t2);
|
||||
bool s = eval_bit_test(t1, m + 1);
|
||||
if(s)
|
||||
{
|
||||
eval_complement(t1, t1);
|
||||
eval_increment(t1);
|
||||
}
|
||||
result = t1;
|
||||
result.sign(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
*result.limbs() &= *o.limbs();
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
>::type
|
||||
eval_bitwise_or(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() |= *o.limbs();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
|
||||
>::type
|
||||
eval_bitwise_or(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_increment;
|
||||
|
||||
if(result.sign() || o.sign())
|
||||
{
|
||||
static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
|
||||
cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
|
||||
cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
|
||||
eval_bitwise_or(t1, t2);
|
||||
bool s = eval_bit_test(t1, m + 1);
|
||||
if(s)
|
||||
{
|
||||
eval_complement(t1, t1);
|
||||
eval_increment(t1);
|
||||
}
|
||||
result = t1;
|
||||
result.sign(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
*result.limbs() |= *o.limbs();
|
||||
result.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
>::type
|
||||
eval_bitwise_xor(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() ^= *o.limbs();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
|
||||
>::type
|
||||
eval_bitwise_xor(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_increment;
|
||||
|
||||
if(result.sign() || o.sign())
|
||||
{
|
||||
static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
|
||||
cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
|
||||
cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
|
||||
eval_bitwise_xor(t1, t2);
|
||||
bool s = eval_bit_test(t1, m + 1);
|
||||
if(s)
|
||||
{
|
||||
eval_complement(t1, t1);
|
||||
eval_increment(t1);
|
||||
}
|
||||
result = t1;
|
||||
result.sign(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
*result.limbs() ^= *o.limbs();
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_CHECKED_HPP
|
||||
#define BOOST_MP_CPP_INT_CHECKED_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{ namespace detail{
|
||||
|
||||
//
|
||||
// Simple routines for performing checked arithmetic with a builtin arithmetic type.
|
||||
// Note that this is not a complete header, it must be included as part of boost/multiprecision/cpp_int.hpp.
|
||||
//
|
||||
|
||||
inline void raise_overflow(std::string op)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("overflow in " + op));
|
||||
}
|
||||
inline void raise_add_overflow()
|
||||
{
|
||||
raise_overflow("addition");
|
||||
}
|
||||
inline void raise_subtract_overflow()
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Subtraction resulted in a negative value, but the type is unsigned"));
|
||||
}
|
||||
inline void raise_mul_overflow()
|
||||
{
|
||||
raise_overflow("multiplication");
|
||||
}
|
||||
inline void raise_div_overflow()
|
||||
{
|
||||
raise_overflow("division");
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline A checked_add_imp(A a, A b, const mpl::true_&)
|
||||
{
|
||||
if(a > 0)
|
||||
{
|
||||
if((b > 0) && ((integer_traits<A>::const_max - b) < a))
|
||||
raise_add_overflow();
|
||||
}
|
||||
else
|
||||
{
|
||||
if((b < 0) && ((integer_traits<A>::const_min - b) > a))
|
||||
raise_add_overflow();
|
||||
}
|
||||
return a + b;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_add_imp(A a, A b, const mpl::false_&)
|
||||
{
|
||||
if((integer_traits<A>::const_max - b) < a)
|
||||
raise_add_overflow();
|
||||
return a + b;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_add(A a, A b, const mpl::int_<checked>&)
|
||||
{
|
||||
return checked_add_imp(a, b, boost::is_signed<A>());
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_add(A a, A b, const mpl::int_<unchecked>&)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline A checked_subtract_imp(A a, A b, const mpl::true_&)
|
||||
{
|
||||
if(a > 0)
|
||||
{
|
||||
if((b < 0) && ((integer_traits<A>::const_max + b) < a))
|
||||
raise_subtract_overflow();
|
||||
}
|
||||
else
|
||||
{
|
||||
if((b > 0) && ((integer_traits<A>::const_min + b) > a))
|
||||
raise_subtract_overflow();
|
||||
}
|
||||
return a - b;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_subtract_imp(A a, A b, const mpl::false_&)
|
||||
{
|
||||
if(a < b)
|
||||
raise_subtract_overflow();
|
||||
return a - b;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_subtract(A a, A b, const mpl::int_<checked>&)
|
||||
{
|
||||
return checked_subtract_imp(a, b, boost::is_signed<A>());
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_subtract(A a, A b, const mpl::int_<unchecked>&)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline A checked_multiply(A a, A b, const mpl::int_<checked>&)
|
||||
{
|
||||
BOOST_MP_USING_ABS
|
||||
if(a && (integer_traits<A>::const_max / abs(a) < abs(b)))
|
||||
raise_mul_overflow();
|
||||
return a * b;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_multiply(A a, A b, const mpl::int_<unchecked>&)
|
||||
{
|
||||
return a * b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline A checked_divide(A a, A b, const mpl::int_<checked>&)
|
||||
{
|
||||
if(b == 0)
|
||||
raise_div_overflow();
|
||||
return a / b;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_divide(A a, A b, const mpl::int_<unchecked>&)
|
||||
{
|
||||
return a / b;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline A checked_left_shift(A a, boost::ulong_long_type shift, const mpl::int_<checked>&)
|
||||
{
|
||||
if(a && shift)
|
||||
{
|
||||
if((shift > sizeof(A) * CHAR_BIT) || (a >> (sizeof(A) * CHAR_BIT - shift)))
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Shift out of range"));
|
||||
}
|
||||
return a << shift;
|
||||
}
|
||||
template <class A>
|
||||
inline A checked_left_shift(A a, boost::ulong_long_type shift, const mpl::int_<unchecked>&)
|
||||
{
|
||||
return (shift >= sizeof(A) * CHAR_BIT) ? 0 : a << shift;
|
||||
}
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_COMPARISON_HPP
|
||||
#define BOOST_MP_CPP_INT_COMPARISON_HPP
|
||||
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4018 4389 4996)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Start with non-trivial cpp_int's:
|
||||
//
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type
|
||||
eval_eq(const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& a, const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
return (a.sign() == b.sign())
|
||||
&& (a.size() == b.size())
|
||||
&& std::equal(a.limbs(), a.limbs() + a.size(),
|
||||
stdext::checked_array_iterator<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::const_limb_pointer>(b.limbs(), b.size()));
|
||||
#else
|
||||
return (a.sign() == b.sign())
|
||||
&& (a.size() == b.size())
|
||||
&& std::equal(a.limbs(), a.limbs() + a.size(), b.limbs());
|
||||
#endif
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value,
|
||||
bool
|
||||
>::type
|
||||
eval_eq(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
return (a.sign() == b.sign())
|
||||
&& (a.size() == b.size())
|
||||
&& std::equal(a.limbs(), a.limbs() + a.size(), stdext::checked_array_iterator<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer>(b.limbs(), b.size()));
|
||||
#else
|
||||
return (a.sign() == b.sign())
|
||||
&& (a.size() == b.size())
|
||||
&& std::equal(a.limbs(), a.limbs() + a.size(), b.limbs());
|
||||
#endif
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (a.sign() == false)
|
||||
&& (a.size() == 1)
|
||||
&& (*a.limbs() == b);
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (a.sign() == (b < 0))
|
||||
&& (a.size() == 1)
|
||||
&& (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b));
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (a.size() == 1)
|
||||
&& (*a.limbs() == b);
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (b < 0) ? eval_eq(a, cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>(b)) : eval_eq(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign())
|
||||
return true;
|
||||
if(a.size() > 1)
|
||||
return false;
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
inline typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
if((b == 0) || (a.sign() != (b < 0)))
|
||||
return a.sign();
|
||||
if(a.sign())
|
||||
{
|
||||
if(a.size() > 1)
|
||||
return true;
|
||||
return *a.limbs() > boost::multiprecision::detail::unsigned_abs(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(a.size() > 1)
|
||||
return false;
|
||||
return *a.limbs() < boost::multiprecision::detail::unsigned_abs(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.size() > 1)
|
||||
return false;
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (b < 0) ? a.compare(b) < 0 : eval_lt(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign())
|
||||
return false;
|
||||
if(a.size() > 1)
|
||||
return true;
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
inline typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(b == 0)
|
||||
return !a.sign() && ((a.size() > 1) || *a.limbs());
|
||||
if(a.sign() != (b < 0))
|
||||
return !a.sign();
|
||||
if(a.sign())
|
||||
{
|
||||
if(a.size() > 1)
|
||||
return false;
|
||||
return *a.limbs() < boost::multiprecision::detail::unsigned_abs(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(a.size() > 1)
|
||||
return true;
|
||||
return *a.limbs() > boost::multiprecision::detail::unsigned_abs(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.size() > 1)
|
||||
return true;
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class Allocator>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>& a, signed_limb_type b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (b < 0) ? a.compare(b) > 0 : eval_gt(a, static_cast<limb_type>(b)); // Use bit pattern of b for comparison.
|
||||
}
|
||||
//
|
||||
// And again for trivial cpp_ints:
|
||||
//
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::value eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (a.sign() == b.sign()) && (*a.limbs() == *b.limbs());
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::value eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
return *a.limbs() == *b.limbs();
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
|
||||
{
|
||||
return !a.sign() && (*a.limbs() == b);
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
|
||||
{
|
||||
return (a.sign() == (b < 0)) && (*a.limbs() == boost::multiprecision::detail::unsigned_abs(b));
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
|
||||
{
|
||||
return *a.limbs() == b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_eq(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
|
||||
{
|
||||
typedef typename make_unsigned<S>::type ui_type;
|
||||
if(b < 0)
|
||||
{
|
||||
cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> t(b);
|
||||
return *a.limbs() == *t.limbs();
|
||||
}
|
||||
else
|
||||
{
|
||||
return *a.limbs() == static_cast<ui_type>(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign() != b.sign())
|
||||
return a.sign();
|
||||
return a.sign() ? *a.limbs() > *b.limbs() : *a.limbs() < *b.limbs();
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
return *a.limbs() < *b.limbs();
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign())
|
||||
return true;
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign() != (b < 0))
|
||||
return a.sign();
|
||||
return a.sign() ? (*a.limbs() > boost::multiprecision::detail::unsigned_abs(b)) : (*a.limbs() < boost::multiprecision::detail::unsigned_abs(b));
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
|
||||
{
|
||||
return *a.limbs() < b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_lt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
|
||||
{
|
||||
typedef typename make_unsigned<S>::type ui_type;
|
||||
if(b < 0)
|
||||
{
|
||||
cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> t(b);
|
||||
return *a.limbs() < *t.limbs();
|
||||
}
|
||||
else
|
||||
{
|
||||
return *a.limbs() < static_cast<ui_type>(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign() != b.sign())
|
||||
return !a.sign();
|
||||
return a.sign() ? *a.limbs() < *b.limbs() : *a.limbs() > *b.limbs();
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
return *a.limbs() > *b.limbs();
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign())
|
||||
return false;
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, signed_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
|
||||
{
|
||||
if(a.sign() != (b < 0))
|
||||
return !a.sign();
|
||||
return a.sign() ? (*a.limbs() < boost::multiprecision::detail::unsigned_abs(b)) : (*a.limbs() > boost::multiprecision::detail::unsigned_abs(b));
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class U>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_unsigned<U>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, U b) BOOST_NOEXCEPT
|
||||
{
|
||||
return *a.limbs() > b;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_int_check_type Checked, class S>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_signed<S>::value && is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> >::value,
|
||||
bool
|
||||
>::type eval_gt(const cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void>& a, S b) BOOST_NOEXCEPT
|
||||
{
|
||||
typedef typename make_unsigned<S>::type ui_type;
|
||||
if(b < 0)
|
||||
{
|
||||
cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, void> t(b);
|
||||
return *a.limbs() > *t.limbs();
|
||||
}
|
||||
else
|
||||
{
|
||||
return *a.limbs() > static_cast<ui_type>(b);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,163 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_CORE_HPP
|
||||
#define BOOST_MP_CPP_INT_CORE_HPP
|
||||
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/integer_traits.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/int.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace detail{
|
||||
|
||||
//
|
||||
// These traits calculate the largest type in the list
|
||||
// [unsigned] boost::long_long_type, long, int, which has the specified number
|
||||
// of bits. Note that intN_t and boost::int_t<N> find the first
|
||||
// member of the above list, not the last. We want the last in the
|
||||
// list to ensure that mixed arithmetic operations are as efficient
|
||||
// as possible.
|
||||
//
|
||||
template <unsigned N>
|
||||
struct largest_signed_type
|
||||
{
|
||||
typedef typename mpl::if_c<
|
||||
1 + std::numeric_limits<boost::long_long_type>::digits == N,
|
||||
boost::long_long_type,
|
||||
typename mpl::if_c<
|
||||
1 + std::numeric_limits<long>::digits == N,
|
||||
long,
|
||||
typename mpl::if_c<
|
||||
1 + std::numeric_limits<int>::digits == N,
|
||||
int,
|
||||
typename boost::int_t<N>::exact
|
||||
>::type
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <unsigned N>
|
||||
struct largest_unsigned_type
|
||||
{
|
||||
typedef typename mpl::if_c<
|
||||
std::numeric_limits<boost::ulong_long_type>::digits == N,
|
||||
boost::ulong_long_type,
|
||||
typename mpl::if_c<
|
||||
std::numeric_limits<unsigned long>::digits == N,
|
||||
unsigned long,
|
||||
typename mpl::if_c<
|
||||
std::numeric_limits<unsigned int>::digits == N,
|
||||
unsigned int,
|
||||
typename boost::uint_t<N>::exact
|
||||
>::type
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
|
||||
typedef detail::largest_unsigned_type<64>::type limb_type;
|
||||
typedef detail::largest_signed_type<64>::type signed_limb_type;
|
||||
typedef boost::uint128_type double_limb_type;
|
||||
typedef boost::int128_type signed_double_limb_type;
|
||||
static const limb_type max_block_10 = 1000000000000000000uLL;
|
||||
static const limb_type digits_per_block_10 = 18;
|
||||
|
||||
inline limb_type block_multiplier(unsigned count)
|
||||
{
|
||||
static const limb_type values[digits_per_block_10]
|
||||
= { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000 };
|
||||
BOOST_ASSERT(count < digits_per_block_10);
|
||||
return values[count];
|
||||
}
|
||||
|
||||
// Can't do formatted IO on an __int128
|
||||
#define BOOST_MP_NO_DOUBLE_LIMB_TYPE_IO
|
||||
|
||||
// Need to specialise integer_traits for __int128 as it's not a normal native type:
|
||||
} // namespace multiprecision
|
||||
|
||||
template<>
|
||||
class integer_traits<multiprecision::double_limb_type>
|
||||
: public std::numeric_limits<multiprecision::double_limb_type>,
|
||||
public detail::integer_traits_base<multiprecision::double_limb_type, 0, ~static_cast<multiprecision::double_limb_type>(0)>
|
||||
{ };
|
||||
template<>
|
||||
class integer_traits<multiprecision::signed_double_limb_type>
|
||||
: public std::numeric_limits<multiprecision::signed_double_limb_type>,
|
||||
public detail::integer_traits_base<multiprecision::signed_double_limb_type, static_cast<multiprecision::signed_double_limb_type>((static_cast<multiprecision::double_limb_type>(1) << 127)), static_cast<multiprecision::signed_double_limb_type>(((~static_cast<multiprecision::double_limb_type>(0)) >> 1))>
|
||||
{ };
|
||||
|
||||
namespace multiprecision{
|
||||
|
||||
#else
|
||||
|
||||
typedef detail::largest_unsigned_type<32>::type limb_type;
|
||||
typedef detail::largest_signed_type<32>::type signed_limb_type;
|
||||
typedef detail::largest_unsigned_type<64>::type double_limb_type;
|
||||
typedef detail::largest_signed_type<64>::type signed_double_limb_type;
|
||||
static const limb_type max_block_10 = 1000000000;
|
||||
static const limb_type digits_per_block_10 = 9;
|
||||
|
||||
inline limb_type block_multiplier(unsigned count)
|
||||
{
|
||||
static const limb_type values[digits_per_block_10]
|
||||
= { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
BOOST_ASSERT(count < digits_per_block_10);
|
||||
return values[count];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const unsigned bits_per_limb = sizeof(limb_type) * CHAR_BIT;
|
||||
|
||||
template <class T>
|
||||
inline void minmax(const T& a, const T& b, T& aa, T& bb)
|
||||
{
|
||||
if(a < b)
|
||||
{
|
||||
aa = a;
|
||||
bb = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
aa = b;
|
||||
bb = a;
|
||||
}
|
||||
}
|
||||
|
||||
enum cpp_integer_type
|
||||
{
|
||||
signed_magnitude = 1,
|
||||
unsigned_magnitude = 0,
|
||||
signed_packed = 3,
|
||||
unsigned_packed = 2
|
||||
};
|
||||
|
||||
enum cpp_int_check_type
|
||||
{
|
||||
checked = 1,
|
||||
unchecked = 0
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
//
|
||||
// Figure out whether to support user-defined-literals or not:
|
||||
//
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_USER_DEFINED_LITERALS) \
|
||||
&& !defined(BOOST_NO_CXX11_CONSTEXPR)
|
||||
# define BOOST_MP_USER_DEFINED_LITERALS
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_CORE_HPP
|
||||
|
||||
@@ -0,0 +1,655 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_DIV_HPP
|
||||
#define BOOST_MP_CPP_INT_DIV_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
void divide_unsigned_helper(
|
||||
CppInt1* result,
|
||||
const CppInt2& x,
|
||||
const CppInt3& y,
|
||||
CppInt1& r)
|
||||
{
|
||||
if(((void*)result == (void*)&x) || ((void*)&r == (void*)&x))
|
||||
{
|
||||
CppInt2 t(x);
|
||||
divide_unsigned_helper(result, t, y, r);
|
||||
return;
|
||||
}
|
||||
if(((void*)result == (void*)&y) || ((void*)&r == (void*)&y))
|
||||
{
|
||||
CppInt3 t(y);
|
||||
divide_unsigned_helper(result, x, t, r);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Very simple, fairly braindead long division.
|
||||
Start by setting the remainder equal to x, and the
|
||||
result equal to 0. Then in each loop we calculate our
|
||||
"best guess" for how many times y divides into r,
|
||||
add our guess to the result, and subtract guess*y
|
||||
from the remainder r. One wrinkle is that the remainder
|
||||
may go negative, in which case we subtract the current guess
|
||||
from the result rather than adding. The value of the guess
|
||||
is determined by dividing the most-significant-limb of the
|
||||
current remainder by the most-significant-limb of y.
|
||||
|
||||
Note that there are more efficient algorithms than this
|
||||
available, in particular see Knuth Vol 2. However for small
|
||||
numbers of limbs this generally outperforms the alternatives
|
||||
and avoids the normalisation step which would require extra storage.
|
||||
*/
|
||||
|
||||
|
||||
using default_ops::eval_subtract;
|
||||
|
||||
if(result == &r)
|
||||
{
|
||||
CppInt1 rem;
|
||||
divide_unsigned_helper(result, x, y, rem);
|
||||
r = rem;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Find the most significant words of numerator and denominator.
|
||||
//
|
||||
limb_type y_order = y.size() - 1;
|
||||
|
||||
if(y_order == 0)
|
||||
{
|
||||
//
|
||||
// Only a single non-zero limb in the denominator, in this case
|
||||
// we can use a specialized divide-by-single-limb routine which is
|
||||
// much faster. This also handles division by zero:
|
||||
//
|
||||
divide_unsigned_helper(result, x, y.limbs()[y_order], r);
|
||||
return;
|
||||
}
|
||||
|
||||
typename CppInt2::const_limb_pointer px = x.limbs();
|
||||
typename CppInt3::const_limb_pointer py = y.limbs();
|
||||
|
||||
limb_type r_order = x.size() - 1;
|
||||
if((r_order == 0) && (*px == 0))
|
||||
{
|
||||
// x is zero, so is the result:
|
||||
r = x;
|
||||
if(result)
|
||||
*result = x;
|
||||
return;
|
||||
}
|
||||
|
||||
r = x;
|
||||
r.sign(false);
|
||||
if(result)
|
||||
*result = static_cast<limb_type>(0u);
|
||||
//
|
||||
// Check if the remainder is already less than the divisor, if so
|
||||
// we already have the result. Note we try and avoid a full compare
|
||||
// if we can:
|
||||
//
|
||||
if(r_order <= y_order)
|
||||
{
|
||||
if((r_order < y_order) || (r.compare_unsigned(y) < 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CppInt1 t;
|
||||
bool r_neg = false;
|
||||
|
||||
//
|
||||
// See if we can short-circuit long division, and use basic arithmetic instead:
|
||||
//
|
||||
if(r_order == 0)
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
*result = px[0] / py[0];
|
||||
}
|
||||
r = px[0] % py[0];
|
||||
return;
|
||||
}
|
||||
else if(r_order == 1)
|
||||
{
|
||||
double_limb_type a, b;
|
||||
a = (static_cast<double_limb_type>(px[1]) << CppInt1::limb_bits) | px[0];
|
||||
b = y_order ?
|
||||
(static_cast<double_limb_type>(py[1]) << CppInt1::limb_bits) | py[0]
|
||||
: py[0];
|
||||
if(result)
|
||||
{
|
||||
*result = a / b;
|
||||
}
|
||||
r = a % b;
|
||||
return;
|
||||
}
|
||||
//
|
||||
// prepare result:
|
||||
//
|
||||
if(result)
|
||||
result->resize(1 + r_order - y_order, 1 + r_order - y_order);
|
||||
typename CppInt1::const_limb_pointer prem = r.limbs();
|
||||
// This is initialised just to keep the compiler from emitting useless warnings later on:
|
||||
typename CppInt1::limb_pointer pr
|
||||
= typename CppInt1::limb_pointer();
|
||||
if(result)
|
||||
{
|
||||
pr = result->limbs();
|
||||
for(unsigned i = 1; i < 1 + r_order - y_order; ++i)
|
||||
pr[i] = 0;
|
||||
}
|
||||
bool first_pass = true;
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Calculate our best guess for how many times y divides into r:
|
||||
//
|
||||
limb_type guess;
|
||||
if((prem[r_order] <= py[y_order]) && (r_order > 0))
|
||||
{
|
||||
double_limb_type a, b, v;
|
||||
a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
|
||||
b = py[y_order];
|
||||
v = a / b;
|
||||
if(v > CppInt1::max_limb_value)
|
||||
guess = 1;
|
||||
else
|
||||
{
|
||||
guess = static_cast<limb_type>(v);
|
||||
--r_order;
|
||||
}
|
||||
}
|
||||
else if(r_order == 0)
|
||||
{
|
||||
guess = prem[0] / py[y_order];
|
||||
}
|
||||
else
|
||||
{
|
||||
double_limb_type a, b, v;
|
||||
a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
|
||||
b = (y_order > 0) ? (static_cast<double_limb_type>(py[y_order]) << CppInt1::limb_bits) | py[y_order - 1] : (static_cast<double_limb_type>(py[y_order]) << CppInt1::limb_bits);
|
||||
v = a / b;
|
||||
guess = static_cast<limb_type>(v);
|
||||
}
|
||||
BOOST_ASSERT(guess); // If the guess ever gets to zero we go on forever....
|
||||
//
|
||||
// Update result:
|
||||
//
|
||||
limb_type shift = r_order - y_order;
|
||||
if(result)
|
||||
{
|
||||
if(r_neg)
|
||||
{
|
||||
if(pr[shift] > guess)
|
||||
pr[shift] -= guess;
|
||||
else
|
||||
{
|
||||
t.resize(shift + 1, shift + 1);
|
||||
t.limbs()[shift] = guess;
|
||||
for(unsigned i = 0; i < shift; ++i)
|
||||
t.limbs()[i] = 0;
|
||||
eval_subtract(*result, t);
|
||||
}
|
||||
}
|
||||
else if(CppInt1::max_limb_value - pr[shift] > guess)
|
||||
pr[shift] += guess;
|
||||
else
|
||||
{
|
||||
t.resize(shift + 1, shift + 1);
|
||||
t.limbs()[shift] = guess;
|
||||
for(unsigned i = 0; i < shift; ++i)
|
||||
t.limbs()[i] = 0;
|
||||
eval_add(*result, t);
|
||||
}
|
||||
}
|
||||
//
|
||||
// Calculate guess * y, we use a fused mutiply-shift O(N) for this
|
||||
// rather than a full O(N^2) multiply:
|
||||
//
|
||||
double_limb_type carry = 0;
|
||||
t.resize(y.size() + shift + 1, y.size() + shift);
|
||||
bool truncated_t = (t.size() != y.size() + shift + 1);
|
||||
typename CppInt1::limb_pointer pt = t.limbs();
|
||||
for(unsigned i = 0; i < shift; ++i)
|
||||
pt[i] = 0;
|
||||
for(unsigned i = 0; i < y.size(); ++i)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(py[i]) * static_cast<double_limb_type>(guess);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pt[i + shift] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
pt[i + shift] = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= CppInt1::limb_bits;
|
||||
}
|
||||
if(carry && !truncated_t)
|
||||
{
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pt[t.size() - 1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
pt[t.size() - 1] = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
}
|
||||
else if(!truncated_t)
|
||||
{
|
||||
t.resize(t.size() - 1, t.size() - 1);
|
||||
}
|
||||
//
|
||||
// Update r in a way that won't actually produce a negative result
|
||||
// in case the argument types are unsigned:
|
||||
//
|
||||
if(truncated_t && carry)
|
||||
{
|
||||
// We need to calculate 2^n + t - r
|
||||
// where n is the number of bits in this type.
|
||||
// Simplest way is to get 2^n - r by complementing
|
||||
// r, then add t to it. Note that we can't call eval_complement
|
||||
// in case this is a signed checked type:
|
||||
for(unsigned i = 0; i <= r_order; ++i)
|
||||
r.limbs()[i] = ~prem[i];
|
||||
r.normalize();
|
||||
eval_increment(r);
|
||||
eval_add(r, t);
|
||||
r_neg = !r_neg;
|
||||
}
|
||||
else if(r.compare(t) > 0)
|
||||
{
|
||||
eval_subtract(r, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
r.swap(t);
|
||||
eval_subtract(r, t);
|
||||
prem = r.limbs();
|
||||
r_neg = !r_neg;
|
||||
}
|
||||
//
|
||||
// First time through we need to strip any leading zero, otherwise
|
||||
// the termination condition goes belly-up:
|
||||
//
|
||||
if(result && first_pass)
|
||||
{
|
||||
first_pass = false;
|
||||
while(pr[result->size() - 1] == 0)
|
||||
result->resize(result->size() - 1, result->size() - 1);
|
||||
}
|
||||
//
|
||||
// Update r_order:
|
||||
//
|
||||
r_order = r.size() - 1;
|
||||
if(r_order < y_order)
|
||||
break;
|
||||
}
|
||||
// Termination condition is really just a check that r > y, but with a common
|
||||
// short-circuit case handled first:
|
||||
while((r_order > y_order) || (r.compare_unsigned(y) >= 0));
|
||||
|
||||
//
|
||||
// We now just have to normalise the result:
|
||||
//
|
||||
if(r_neg && eval_get_sign(r))
|
||||
{
|
||||
// We have one too many in the result:
|
||||
if(result)
|
||||
eval_decrement(*result);
|
||||
if(y.sign())
|
||||
{
|
||||
r.negate();
|
||||
eval_subtract(r, y);
|
||||
}
|
||||
else
|
||||
eval_subtract(r, y, r);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(r.compare_unsigned(y) < 0); // remainder must be less than the divisor or our code has failed
|
||||
}
|
||||
|
||||
template <class CppInt1, class CppInt2>
|
||||
void divide_unsigned_helper(
|
||||
CppInt1* result,
|
||||
const CppInt2& x,
|
||||
limb_type y,
|
||||
CppInt1& r)
|
||||
{
|
||||
if(((void*)result == (void*)&x) || ((void*)&r == (void*)&x))
|
||||
{
|
||||
CppInt2 t(x);
|
||||
divide_unsigned_helper(result, t, y, r);
|
||||
return;
|
||||
}
|
||||
|
||||
if(result == &r)
|
||||
{
|
||||
CppInt1 rem;
|
||||
divide_unsigned_helper(result, x, y, rem);
|
||||
r = rem;
|
||||
return;
|
||||
}
|
||||
|
||||
// As above, but simplified for integer divisor:
|
||||
|
||||
using default_ops::eval_subtract;
|
||||
|
||||
if(y == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Integer Division by zero."));
|
||||
}
|
||||
//
|
||||
// Find the most significant word of numerator.
|
||||
//
|
||||
limb_type r_order = x.size() - 1;
|
||||
|
||||
//
|
||||
// Set remainder and result to their initial values:
|
||||
//
|
||||
r = x;
|
||||
r.sign(false);
|
||||
typename CppInt1::limb_pointer pr = r.limbs();
|
||||
|
||||
//
|
||||
// check for x < y, try to do this without actually having to
|
||||
// do a full comparison:
|
||||
//
|
||||
if((r_order == 0) && (*pr < y))
|
||||
{
|
||||
if(result)
|
||||
*result = static_cast<limb_type>(0u);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// See if we can short-circuit long division, and use basic arithmetic instead:
|
||||
//
|
||||
if(r_order == 0)
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
*result = *pr / y;
|
||||
result->sign(x.sign());
|
||||
}
|
||||
*pr %= y;
|
||||
r.sign(x.sign());
|
||||
return;
|
||||
}
|
||||
else if(r_order == 1)
|
||||
{
|
||||
double_limb_type a;
|
||||
a = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[0];
|
||||
if(result)
|
||||
{
|
||||
*result = a / y;
|
||||
result->sign(x.sign());
|
||||
}
|
||||
r = a % y;
|
||||
r.sign(x.sign());
|
||||
return;
|
||||
}
|
||||
|
||||
// This is initialised just to keep the compiler from emitting useless warnings later on:
|
||||
typename CppInt1::limb_pointer pres = typename CppInt1::limb_pointer();
|
||||
if(result)
|
||||
{
|
||||
result->resize(r_order + 1, r_order + 1);
|
||||
pres = result->limbs();
|
||||
if(result->size() > r_order)
|
||||
pres[r_order] = 0; // just in case we don't set the most significant limb below.
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Calculate our best guess for how many times y divides into r:
|
||||
//
|
||||
if((pr[r_order] < y) && r_order)
|
||||
{
|
||||
double_limb_type a, b;
|
||||
a = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[r_order - 1];
|
||||
b = a % y;
|
||||
r.resize(r.size() - 1, r.size() - 1);
|
||||
--r_order;
|
||||
pr[r_order] = static_cast<limb_type>(b);
|
||||
if(result)
|
||||
pres[r_order] = static_cast<limb_type>(a / y);
|
||||
if(r_order && pr[r_order] == 0)
|
||||
{
|
||||
--r_order; // No remainder, division was exact.
|
||||
r.resize(r.size() - 1, r.size() - 1);
|
||||
if(result)
|
||||
pres[r_order] = static_cast<limb_type>(0u);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(result)
|
||||
pres[r_order] = pr[r_order] / y;
|
||||
pr[r_order] %= y;
|
||||
if(r_order && pr[r_order] == 0)
|
||||
{
|
||||
--r_order; // No remainder, division was exact.
|
||||
r.resize(r.size() - 1, r.size() - 1);
|
||||
if(result)
|
||||
pres[r_order] = static_cast<limb_type>(0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Termination condition is really just a check that r >= y, but with two common
|
||||
// short-circuit cases handled first:
|
||||
while(r_order || (pr[r_order] >= y));
|
||||
|
||||
if(result)
|
||||
{
|
||||
result->normalize();
|
||||
result->sign(x.sign());
|
||||
}
|
||||
r.normalize();
|
||||
r.sign(x.sign());
|
||||
|
||||
BOOST_ASSERT(r.compare(y) < 0); // remainder must be less than the divisor or our code has failed
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
|
||||
bool s = a.sign() != b.sign();
|
||||
divide_unsigned_helper(&result, a, b, r);
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
limb_type& b)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
|
||||
bool s = a.sign();
|
||||
divide_unsigned_helper(&result, a, b, r);
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
signed_limb_type& b)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
|
||||
bool s = a.sign() != (b < 0);
|
||||
divide_unsigned_helper(&result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(b)), r);
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b)
|
||||
{
|
||||
// There is no in place divide:
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
|
||||
eval_divide(result, a, b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
limb_type b)
|
||||
{
|
||||
// There is no in place divide:
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
|
||||
eval_divide(result, a, b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
signed_limb_type b)
|
||||
{
|
||||
// There is no in place divide:
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
|
||||
eval_divide(result, a, b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
|
||||
{
|
||||
bool s = a.sign();
|
||||
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>* >(0), a, b, result);
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a, limb_type b)
|
||||
{
|
||||
bool s = a.sign();
|
||||
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>* >(0), a, b, result);
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
signed_limb_type b)
|
||||
{
|
||||
bool s = a.sign();
|
||||
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>* >(0), a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(b)), result);
|
||||
result.sign(s);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b)
|
||||
{
|
||||
// There is no in place divide:
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
|
||||
eval_modulus(result, a, b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
limb_type b)
|
||||
{
|
||||
// There is no in place divide:
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
|
||||
eval_modulus(result, a, b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
signed_limb_type b)
|
||||
{
|
||||
// There is no in place divide:
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
|
||||
eval_modulus(result, a, b);
|
||||
}
|
||||
|
||||
//
|
||||
// Over again for trivial cpp_int's:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
|
||||
{
|
||||
if(!*o.limbs())
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
|
||||
*result.limbs() /= *o.limbs();
|
||||
result.sign(result.sign() != o.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_divide(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
|
||||
{
|
||||
if(!*o.limbs())
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
|
||||
*result.limbs() /= *o.limbs();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_modulus(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
|
||||
{
|
||||
if(!*o.limbs())
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Division by zero."));
|
||||
*result.limbs() %= *o.limbs();
|
||||
result.sign(result.sign());
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,251 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2015 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
#define BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Backend, class Unsigned>
|
||||
void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::false_& tag)
|
||||
{
|
||||
unsigned limb = bit_location / (sizeof(limb_type) * CHAR_BIT);
|
||||
unsigned shift = bit_location % (sizeof(limb_type) * CHAR_BIT);
|
||||
|
||||
limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT ? ~static_cast<limb_type>(0u) : (static_cast<limb_type>(1u) << chunk_bits) - 1;
|
||||
|
||||
limb_type value = static_cast<limb_type>(bits & mask) << shift;
|
||||
if(value)
|
||||
{
|
||||
if(val.size() == limb)
|
||||
{
|
||||
val.resize(limb + 1, limb + 1);
|
||||
if(val.size() > limb)
|
||||
val.limbs()[limb] = value;
|
||||
}
|
||||
else if(val.size() > limb)
|
||||
val.limbs()[limb] |= value;
|
||||
}
|
||||
if(chunk_bits > sizeof(limb_type) * CHAR_BIT - shift)
|
||||
{
|
||||
shift = sizeof(limb_type) * CHAR_BIT - shift;
|
||||
chunk_bits -= shift;
|
||||
bit_location += shift;
|
||||
bits >>= shift;
|
||||
if(bits)
|
||||
assign_bits(val, bits, bit_location, chunk_bits, tag);
|
||||
}
|
||||
}
|
||||
template <class Backend, class Unsigned>
|
||||
void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::true_&)
|
||||
{
|
||||
typedef typename Backend::local_limb_type local_limb_type;
|
||||
//
|
||||
// Check for possible overflow, this may trigger an exception, or have no effect
|
||||
// depending on whether this is a checked integer or not:
|
||||
//
|
||||
if((bit_location >= sizeof(local_limb_type) * CHAR_BIT) && bits)
|
||||
val.resize(2, 2);
|
||||
else
|
||||
{
|
||||
local_limb_type mask = chunk_bits >= sizeof(local_limb_type) * CHAR_BIT ? ~static_cast<local_limb_type>(0u) : (static_cast<local_limb_type>(1u) << chunk_bits) - 1;
|
||||
local_limb_type value = (static_cast<local_limb_type>(bits) & mask) << bit_location;
|
||||
*val.limbs() |= value;
|
||||
//
|
||||
// Check for overflow bits:
|
||||
//
|
||||
bit_location = sizeof(local_limb_type) * CHAR_BIT - bit_location;
|
||||
if((bit_location < sizeof(bits)*CHAR_BIT) && (bits >>= bit_location))
|
||||
val.resize(2, 2); // May throw!
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned bits, const mpl::false_&)
|
||||
{
|
||||
unsigned limb_count = static_cast<unsigned>(bits / (sizeof(limb_type) * CHAR_BIT));
|
||||
if(bits % (sizeof(limb_type) * CHAR_BIT))
|
||||
++limb_count;
|
||||
static const unsigned max_limbs = MaxBits ? MaxBits / (CHAR_BIT * sizeof(limb_type)) + ((MaxBits % (CHAR_BIT * sizeof(limb_type))) ? 1 : 0) : (std::numeric_limits<unsigned>::max)();
|
||||
if(limb_count > max_limbs)
|
||||
limb_count = max_limbs;
|
||||
newval.resize(limb_count, limb_count);
|
||||
std::memset(newval.limbs(), 0, newval.size() * sizeof(limb_type));
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned, const mpl::true_&)
|
||||
{
|
||||
*newval.limbs() = 0;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
||||
import_bits_generic(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
typename number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>::backend_type newval;
|
||||
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
typedef typename boost::make_unsigned<value_type>::type unsigned_value_type;
|
||||
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
|
||||
typedef typename boost::make_unsigned<difference_type>::type size_type;
|
||||
typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
|
||||
|
||||
if(!chunk_size)
|
||||
chunk_size = std::numeric_limits<value_type>::digits;
|
||||
|
||||
size_type limbs = std::distance(i, j);
|
||||
size_type bits = limbs * chunk_size;
|
||||
|
||||
detail::resize_to_bit_size(newval, static_cast<unsigned>(bits), tag_type());
|
||||
|
||||
difference_type bit_location = msv_first ? bits - chunk_size : 0;
|
||||
difference_type bit_location_change = msv_first ? -static_cast<difference_type>(chunk_size) : chunk_size;
|
||||
|
||||
while(i != j)
|
||||
{
|
||||
detail::assign_bits(newval, static_cast<unsigned_value_type>(*i), static_cast<unsigned>(bit_location), chunk_size, tag_type());
|
||||
++i;
|
||||
bit_location += bit_location_change;
|
||||
}
|
||||
|
||||
newval.normalize();
|
||||
|
||||
val.backend().swap(newval);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline typename boost::disable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type
|
||||
import_bits_fast(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
|
||||
{
|
||||
std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
|
||||
std::size_t limb_len = byte_len / sizeof(limb_type);
|
||||
if(byte_len % sizeof(limb_type))
|
||||
++limb_len;
|
||||
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
|
||||
result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data!
|
||||
result.limbs()[result.size() - 1] = 0u;
|
||||
std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(limb_type)));
|
||||
result.normalize(); // In case data has leading zeros.
|
||||
return val;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline typename boost::enable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type
|
||||
import_bits_fast(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
|
||||
{
|
||||
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
|
||||
std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
|
||||
std::size_t limb_len = byte_len / sizeof(result.limbs()[0]);
|
||||
if(byte_len % sizeof(result.limbs()[0]))
|
||||
++limb_len;
|
||||
result.limbs()[0] = 0u;
|
||||
result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data!
|
||||
std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(result.limbs()[0])));
|
||||
result.normalize(); // In case data has leading zeros.
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
|
||||
inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
||||
import_bits(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
||||
import_bits(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
if(((chunk_size % CHAR_BIT) == 0) && !msv_first)
|
||||
return detail::import_bits_fast(val, i, j, chunk_size);
|
||||
#endif
|
||||
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Backend>
|
||||
boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::false_& tag)
|
||||
{
|
||||
unsigned limb = location / (sizeof(limb_type) * CHAR_BIT);
|
||||
unsigned shift = location % (sizeof(limb_type) * CHAR_BIT);
|
||||
boost::uintmax_t result = 0;
|
||||
boost::uintmax_t mask = count == std::numeric_limits<boost::uintmax_t>::digits ? ~static_cast<boost::uintmax_t>(0) : (static_cast<boost::uintmax_t>(1u) << count) - 1;
|
||||
if(count > (sizeof(limb_type) * CHAR_BIT - shift))
|
||||
{
|
||||
result = extract_bits(val, location + sizeof(limb_type) * CHAR_BIT - shift, count - sizeof(limb_type) * CHAR_BIT + shift, tag);
|
||||
result <<= sizeof(limb_type) * CHAR_BIT - shift;
|
||||
}
|
||||
if(limb < val.size())
|
||||
result |= (val.limbs()[limb] >> shift) & mask;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::true_&)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class OutputIterator>
|
||||
OutputIterator export_bits(
|
||||
const number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, OutputIterator out, unsigned chunk_size, bool msv_first = true)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
|
||||
if(!val)
|
||||
{
|
||||
*out = 0;
|
||||
++out;
|
||||
return out;
|
||||
}
|
||||
unsigned bitcount = boost::multiprecision::backends::eval_msb_imp(val.backend()) + 1;
|
||||
unsigned chunks = bitcount / chunk_size;
|
||||
if(bitcount % chunk_size)
|
||||
++chunks;
|
||||
|
||||
int bit_location = msv_first ? bitcount - chunk_size : 0;
|
||||
int bit_step = msv_first ? -static_cast<int>(chunk_size) : chunk_size;
|
||||
while(bit_location % bit_step) ++bit_location;
|
||||
|
||||
do
|
||||
{
|
||||
*out = detail::extract_bits(val.backend(), bit_location, chunk_size, tag_type());
|
||||
++out;
|
||||
bit_location += bit_step;
|
||||
} while((bit_location >= 0) && (bit_location < (int)bitcount));
|
||||
|
||||
return out;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_LIM_HPP
|
||||
#define BOOST_MP_CPP_INT_LIM_HPP
|
||||
|
||||
namespace std{
|
||||
|
||||
namespace detail{
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4307)
|
||||
#endif
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const boost::mpl::true_&, const boost::mpl::true_&)
|
||||
{
|
||||
// Bounded and signed.
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> result_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MaxBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>, ExpressionTemplates> ui_type;
|
||||
static const result_type val = -result_type(~ui_type(0));
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const boost::mpl::true_&, const boost::mpl::false_&)
|
||||
{
|
||||
// Bounded and unsigned:
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const boost::mpl::false_&, const boost::mpl::true_&)
|
||||
{
|
||||
// Unbounded and signed.
|
||||
// There is no minimum value, just return 0:
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_min(const boost::mpl::false_&, const boost::mpl::false_&)
|
||||
{
|
||||
// Unbound and unsigned:
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const boost::mpl::true_&, const boost::mpl::true_&)
|
||||
{
|
||||
// Bounded and signed.
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> result_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MaxBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked>, ExpressionTemplates> ui_type;
|
||||
static const result_type val = ~ui_type(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const boost::mpl::true_&, const boost::mpl::false_&)
|
||||
{
|
||||
// Bound and unsigned:
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> result_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, Allocator>, ExpressionTemplates> ui_type;
|
||||
static const result_type val = ~ui_type(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const boost::mpl::false_&, const boost::mpl::true_&)
|
||||
{
|
||||
// Unbounded and signed.
|
||||
// There is no maximum value, just return 0:
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>
|
||||
get_max(const boost::mpl::false_&, const boost::mpl::false_&)
|
||||
{
|
||||
// Unbound and unsigned:
|
||||
static const boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> val(0u);
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >
|
||||
{
|
||||
typedef boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> backend_type;
|
||||
typedef boost::multiprecision::number<backend_type, ExpressionTemplates> number_type;
|
||||
|
||||
struct inititializer
|
||||
{
|
||||
inititializer()
|
||||
{
|
||||
(std::numeric_limits<number_type>::max)();
|
||||
(std::numeric_limits<number_type>::min)();
|
||||
}
|
||||
void do_nothing()const{}
|
||||
};
|
||||
|
||||
static const inititializer init;
|
||||
|
||||
public:
|
||||
BOOST_STATIC_CONSTEXPR bool is_specialized = true;
|
||||
//
|
||||
// Largest and smallest numbers are bounded only by available memory, set
|
||||
// to zero:
|
||||
//
|
||||
static number_type (min)()
|
||||
{
|
||||
init.do_nothing();
|
||||
return detail::get_min<MinBits, MaxBits, SignType, Checked, Allocator, ExpressionTemplates>(boost::multiprecision::backends::is_fixed_precision<backend_type>(), boost::multiprecision::is_signed_number<backend_type>());
|
||||
}
|
||||
static number_type (max)()
|
||||
{
|
||||
init.do_nothing();
|
||||
return detail::get_max<MinBits, MaxBits, SignType, Checked, Allocator, ExpressionTemplates>(boost::multiprecision::backends::is_fixed_precision<backend_type>(), boost::multiprecision::is_signed_number<backend_type>());
|
||||
}
|
||||
static number_type lowest() { return (min)(); }
|
||||
BOOST_STATIC_CONSTEXPR int digits = boost::multiprecision::backends::max_precision<backend_type>::value == UINT_MAX ? INT_MAX : boost::multiprecision::backends::max_precision<backend_type>::value;
|
||||
BOOST_STATIC_CONSTEXPR int digits10 = (digits > INT_MAX / 301) ? (digits / 1000) * 301L : (digits * 301) / 1000;
|
||||
BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 3;
|
||||
BOOST_STATIC_CONSTEXPR bool is_signed = boost::multiprecision::is_signed_number<backend_type>::value;
|
||||
BOOST_STATIC_CONSTEXPR bool is_integer = true;
|
||||
BOOST_STATIC_CONSTEXPR bool is_exact = true;
|
||||
BOOST_STATIC_CONSTEXPR int radix = 2;
|
||||
static number_type epsilon() { return 0; }
|
||||
static number_type round_error() { return 0; }
|
||||
BOOST_STATIC_CONSTEXPR int min_exponent = 0;
|
||||
BOOST_STATIC_CONSTEXPR int min_exponent10 = 0;
|
||||
BOOST_STATIC_CONSTEXPR int max_exponent = 0;
|
||||
BOOST_STATIC_CONSTEXPR int max_exponent10 = 0;
|
||||
BOOST_STATIC_CONSTEXPR bool has_infinity = false;
|
||||
BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false;
|
||||
BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false;
|
||||
BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent;
|
||||
BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false;
|
||||
static number_type infinity() { return 0; }
|
||||
static number_type quiet_NaN() { return 0; }
|
||||
static number_type signaling_NaN() { return 0; }
|
||||
static number_type denorm_min() { return 0; }
|
||||
BOOST_STATIC_CONSTEXPR bool is_iec559 = false;
|
||||
BOOST_STATIC_CONSTEXPR bool is_bounded = boost::multiprecision::backends::is_fixed_precision<backend_type>::value;
|
||||
BOOST_STATIC_CONSTEXPR bool is_modulo = (boost::multiprecision::backends::is_fixed_precision<backend_type>::value && (Checked == boost::multiprecision::unchecked));
|
||||
BOOST_STATIC_CONSTEXPR bool traps = false;
|
||||
BOOST_STATIC_CONSTEXPR bool tinyness_before = false;
|
||||
BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero;
|
||||
};
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
const typename numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::inititializer numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::init;
|
||||
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::digits;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::digits10;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_digits10;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_signed;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_integer;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_exact;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::radix;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::min_exponent;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::min_exponent10;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_exponent;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::max_exponent10;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_infinity;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_quiet_NaN;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_signaling_NaN;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_denorm;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::has_denorm_loss;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_iec559;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_bounded;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::is_modulo;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::traps;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::tinyness_before;
|
||||
template <unsigned MinBits, unsigned MaxBits, boost::multiprecision::cpp_integer_type SignType, boost::multiprecision::cpp_int_check_type Checked, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates> >::round_style;
|
||||
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_LITERALS_HPP
|
||||
#define BOOST_MP_CPP_INT_LITERALS_HPP
|
||||
|
||||
#include <boost/multiprecision/cpp_int/cpp_int_config.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace literals{ namespace detail{
|
||||
|
||||
template <char> struct hex_value;
|
||||
template <> struct hex_value<'0'> { static constexpr limb_type value = 0; };
|
||||
template <> struct hex_value<'1'> { static constexpr limb_type value = 1; };
|
||||
template <> struct hex_value<'2'> { static constexpr limb_type value = 2; };
|
||||
template <> struct hex_value<'3'> { static constexpr limb_type value = 3; };
|
||||
template <> struct hex_value<'4'> { static constexpr limb_type value = 4; };
|
||||
template <> struct hex_value<'5'> { static constexpr limb_type value = 5; };
|
||||
template <> struct hex_value<'6'> { static constexpr limb_type value = 6; };
|
||||
template <> struct hex_value<'7'> { static constexpr limb_type value = 7; };
|
||||
template <> struct hex_value<'8'> { static constexpr limb_type value = 8; };
|
||||
template <> struct hex_value<'9'> { static constexpr limb_type value = 9; };
|
||||
template <> struct hex_value<'a'> { static constexpr limb_type value = 10; };
|
||||
template <> struct hex_value<'b'> { static constexpr limb_type value = 11; };
|
||||
template <> struct hex_value<'c'> { static constexpr limb_type value = 12; };
|
||||
template <> struct hex_value<'d'> { static constexpr limb_type value = 13; };
|
||||
template <> struct hex_value<'e'> { static constexpr limb_type value = 14; };
|
||||
template <> struct hex_value<'f'> { static constexpr limb_type value = 15; };
|
||||
template <> struct hex_value<'A'> { static constexpr limb_type value = 10; };
|
||||
template <> struct hex_value<'B'> { static constexpr limb_type value = 11; };
|
||||
template <> struct hex_value<'C'> { static constexpr limb_type value = 12; };
|
||||
template <> struct hex_value<'D'> { static constexpr limb_type value = 13; };
|
||||
template <> struct hex_value<'E'> { static constexpr limb_type value = 14; };
|
||||
template <> struct hex_value<'F'> { static constexpr limb_type value = 15; };
|
||||
|
||||
template <class Pack, limb_type value>
|
||||
struct combine_value_to_pack;
|
||||
template <limb_type first, limb_type...ARGS, limb_type value>
|
||||
struct combine_value_to_pack<value_pack<first, ARGS...>, value>
|
||||
{
|
||||
typedef value_pack<first | value, ARGS...> type;
|
||||
};
|
||||
|
||||
template <char NextChar, char...CHARS>
|
||||
struct pack_values
|
||||
{
|
||||
static constexpr unsigned chars_per_limb = sizeof(limb_type) * CHAR_BIT / 4;
|
||||
static constexpr unsigned shift = ((sizeof...(CHARS)) % chars_per_limb) * 4;
|
||||
static constexpr limb_type value_to_add = shift ? hex_value<NextChar>::value << shift : hex_value<NextChar>::value;
|
||||
|
||||
typedef typename pack_values<CHARS...>::type recursive_packed_type;
|
||||
typedef typename boost::mpl::if_c<shift == 0,
|
||||
typename recursive_packed_type::next_type,
|
||||
recursive_packed_type>::type pack_type;
|
||||
typedef typename combine_value_to_pack<pack_type, value_to_add>::type type;
|
||||
};
|
||||
template <char NextChar>
|
||||
struct pack_values<NextChar>
|
||||
{
|
||||
static constexpr limb_type value_to_add = hex_value<NextChar>::value;
|
||||
|
||||
typedef value_pack<value_to_add> type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct strip_leading_zeros_from_pack;
|
||||
template <limb_type...PACK>
|
||||
struct strip_leading_zeros_from_pack<value_pack<PACK...> >
|
||||
{
|
||||
typedef value_pack<PACK...> type;
|
||||
};
|
||||
template <limb_type...PACK>
|
||||
struct strip_leading_zeros_from_pack<value_pack<0u, PACK...> >
|
||||
{
|
||||
typedef typename strip_leading_zeros_from_pack<value_pack<PACK...> >::type type;
|
||||
};
|
||||
|
||||
template <limb_type v, class PACK>
|
||||
struct append_value_to_pack;
|
||||
template <limb_type v, limb_type...PACK>
|
||||
struct append_value_to_pack<v, value_pack<PACK...> >
|
||||
{
|
||||
typedef value_pack<PACK..., v> type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct reverse_value_pack;
|
||||
template <limb_type v, limb_type...VALUES>
|
||||
struct reverse_value_pack<value_pack<v, VALUES...> >
|
||||
{
|
||||
typedef typename reverse_value_pack<value_pack<VALUES...> >::type lead_values;
|
||||
typedef typename append_value_to_pack<v, lead_values>::type type;
|
||||
};
|
||||
template <limb_type v>
|
||||
struct reverse_value_pack<value_pack<v> >
|
||||
{
|
||||
typedef value_pack<v> type;
|
||||
};
|
||||
template <>
|
||||
struct reverse_value_pack<value_pack<> >
|
||||
{
|
||||
typedef value_pack<> type;
|
||||
};
|
||||
|
||||
template <char l1, char l2, char...STR>
|
||||
struct make_packed_value_from_str
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(l1 == '0', "Multi-precision integer literals must be in hexadecimal notation.");
|
||||
BOOST_STATIC_ASSERT_MSG((l2 == 'X') || (l2 == 'x'), "Multi-precision integer literals must be in hexadecimal notation.");
|
||||
typedef typename pack_values<STR...>::type packed_type;
|
||||
typedef typename strip_leading_zeros_from_pack<packed_type>::type stripped_type;
|
||||
typedef typename reverse_value_pack<stripped_type>::type type;
|
||||
};
|
||||
|
||||
template <class Pack, class B>
|
||||
struct make_backend_from_pack
|
||||
{
|
||||
static constexpr Pack p = {};
|
||||
static constexpr B value = p;
|
||||
};
|
||||
|
||||
template <class Pack, class B>
|
||||
constexpr B make_backend_from_pack<Pack, B>::value;
|
||||
|
||||
template <unsigned Digits>
|
||||
struct signed_cpp_int_literal_result_type
|
||||
{
|
||||
static constexpr unsigned bits = Digits * 4;
|
||||
typedef boost::multiprecision::backends::cpp_int_backend<bits, bits, signed_magnitude, unchecked, void> backend_type;
|
||||
typedef number<backend_type, et_off> number_type;
|
||||
};
|
||||
|
||||
template <unsigned Digits>
|
||||
struct unsigned_cpp_int_literal_result_type
|
||||
{
|
||||
static constexpr unsigned bits = Digits * 4;
|
||||
typedef boost::multiprecision::backends::cpp_int_backend<bits, bits, unsigned_magnitude, unchecked, void> backend_type;
|
||||
typedef number<backend_type, et_off> number_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <char... STR>
|
||||
constexpr typename boost::multiprecision::literals::detail::signed_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::number_type operator "" _cppi()
|
||||
{
|
||||
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;
|
||||
return boost::multiprecision::literals::detail::make_backend_from_pack<pt, typename boost::multiprecision::literals::detail::signed_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::backend_type>::value;
|
||||
}
|
||||
|
||||
template <char... STR>
|
||||
constexpr typename boost::multiprecision::literals::detail::unsigned_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::number_type operator "" _cppui()
|
||||
{
|
||||
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;
|
||||
return boost::multiprecision::literals::detail::make_backend_from_pack<pt, typename boost::multiprecision::literals::detail::unsigned_cpp_int_literal_result_type<(sizeof...(STR)) - 2>::backend_type>::value;
|
||||
}
|
||||
|
||||
#define BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(Bits)\
|
||||
template <char... STR> \
|
||||
constexpr boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> > operator "" BOOST_JOIN(_cppi, Bits)()\
|
||||
{\
|
||||
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;\
|
||||
return boost::multiprecision::literals::detail::make_backend_from_pack<\
|
||||
pt, \
|
||||
boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> \
|
||||
>::value;\
|
||||
}\
|
||||
template <char... STR> \
|
||||
constexpr boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void> > operator "" BOOST_JOIN(_cppui, Bits)()\
|
||||
{\
|
||||
typedef typename boost::multiprecision::literals::detail::make_packed_value_from_str<STR...>::type pt;\
|
||||
return boost::multiprecision::literals::detail::make_backend_from_pack<\
|
||||
pt, \
|
||||
boost::multiprecision::backends::cpp_int_backend<Bits, Bits, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>\
|
||||
>::value;\
|
||||
}\
|
||||
|
||||
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(128)
|
||||
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(256)
|
||||
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(512)
|
||||
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(1024)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Overload unary minus operator for constexpr use:
|
||||
//
|
||||
template <unsigned MinBits, cpp_int_check_type Checked>
|
||||
constexpr number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>
|
||||
operator - (const number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>& a)
|
||||
{
|
||||
return cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>(a.backend(), boost::multiprecision::literals::detail::make_negate_tag());
|
||||
}
|
||||
template <unsigned MinBits, cpp_int_check_type Checked>
|
||||
constexpr number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>
|
||||
operator - (number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>&& a)
|
||||
{
|
||||
return cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>(static_cast<const number<cpp_int_backend<MinBits, MinBits, signed_magnitude, Checked, void>, et_off>&>(a).backend(), boost::multiprecision::literals::detail::make_negate_tag());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_CORE_HPP
|
||||
|
||||
@@ -0,0 +1,713 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_MISC_HPP
|
||||
#define BOOST_MP_CPP_INT_MISC_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
|
||||
#include <boost/integer/common_factor_rt.hpp> // gcd/lcm
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4702)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
template <class R, class CppInt>
|
||||
void check_in_range(const CppInt& val, const mpl::int_<checked>&)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<R, CppInt>::type cast_type;
|
||||
if(val.sign())
|
||||
{
|
||||
if(boost::is_signed<R>::value == false)
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
|
||||
if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::min)())) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::max)())) > 0)
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
|
||||
}
|
||||
}
|
||||
template <class R, class CppInt>
|
||||
inline void check_in_range(const CppInt& /*val*/, const mpl::int_<unchecked>&) BOOST_NOEXCEPT {}
|
||||
|
||||
inline void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {}
|
||||
inline void check_is_negative(const mpl::false_&)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
inline Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT
|
||||
{
|
||||
return -i;
|
||||
}
|
||||
template <class Integer>
|
||||
inline Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT
|
||||
{
|
||||
return ~(i-1);
|
||||
}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend)
|
||||
{
|
||||
typedef mpl::int_<Checked1> checked_type;
|
||||
check_in_range<R>(backend, checked_type());
|
||||
|
||||
if (std::numeric_limits<R>::digits < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
|
||||
{
|
||||
if ((backend.sign() && boost::is_signed<R>::value) && (1 + static_cast<boost::multiprecision::limb_type>((std::numeric_limits<R>::max)()) <= backend.limbs()[0]))
|
||||
{
|
||||
*result = (std::numeric_limits<R>::min)();
|
||||
return;
|
||||
}
|
||||
else if (boost::is_signed<R>::value && !backend.sign() && static_cast<boost::multiprecision::limb_type>((std::numeric_limits<R>::max)()) <= backend.limbs()[0])
|
||||
{
|
||||
*result = (std::numeric_limits<R>::max)();
|
||||
return;
|
||||
}
|
||||
else
|
||||
*result = static_cast<R>(backend.limbs()[0]);
|
||||
}
|
||||
else
|
||||
*result = static_cast<R>(backend.limbs()[0]);
|
||||
unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned i = 1;
|
||||
if (std::numeric_limits<R>::digits > cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)
|
||||
{
|
||||
while ((i < backend.size()) && (shift < static_cast<unsigned>(std::numeric_limits<R>::digits - cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits)))
|
||||
{
|
||||
*result += static_cast<R>(backend.limbs()[i]) << shift;
|
||||
shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
++i;
|
||||
}
|
||||
//
|
||||
// We have one more limb to extract, but may not need all the bits, so treat this as a special case:
|
||||
//
|
||||
if (i < backend.size())
|
||||
{
|
||||
static const limb_type mask = std::numeric_limits<R>::digits - shift == cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits ?
|
||||
~static_cast<limb_type>(0) : (static_cast<limb_type>(1u) << (std::numeric_limits<R>::digits - shift)) - 1;
|
||||
*result += (static_cast<R>(backend.limbs()[i]) & mask) << shift;
|
||||
if ((static_cast<R>(backend.limbs()[i]) & static_cast<limb_type>(~mask)) || (i + 1 < backend.size()))
|
||||
{
|
||||
// Overflow:
|
||||
if (backend.sign())
|
||||
{
|
||||
check_is_negative(boost::is_signed<R>());
|
||||
*result = (std::numeric_limits<R>::min)();
|
||||
}
|
||||
else if(boost::is_signed<R>::value)
|
||||
*result = (std::numeric_limits<R>::max)();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (backend.size() > 1)
|
||||
{
|
||||
// Overflow:
|
||||
if (backend.sign())
|
||||
{
|
||||
check_is_negative(boost::is_signed<R>());
|
||||
*result = (std::numeric_limits<R>::min)();
|
||||
}
|
||||
else if(boost::is_signed<R>::value)
|
||||
*result = (std::numeric_limits<R>::max)();
|
||||
return;
|
||||
}
|
||||
if(backend.sign())
|
||||
{
|
||||
check_is_negative(boost::is_signed<R>());
|
||||
*result = negate_integer(*result, boost::is_signed<R>());
|
||||
}
|
||||
}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_floating_point<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_MP_NOEXCEPT_IF(is_arithmetic<R>::value)
|
||||
{
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
|
||||
unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
*result = static_cast<R>(*p);
|
||||
for(unsigned i = 1; i < backend.size(); ++i)
|
||||
{
|
||||
*result += static_cast<R>(std::ldexp(static_cast<long double>(p[i]), shift));
|
||||
shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
}
|
||||
if(backend.sign())
|
||||
*result = -*result;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
|
||||
eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
return (val.size() == 1) && (val.limbs()[0] == 0);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
|
||||
eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
result = val;
|
||||
result.sign(false);
|
||||
}
|
||||
|
||||
//
|
||||
// Get the location of the least-significant-bit:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
|
||||
//
|
||||
// Find the index of the least significant limb that is non-zero:
|
||||
//
|
||||
unsigned index = 0;
|
||||
while(!a.limbs()[index] && (index < a.size()))
|
||||
++index;
|
||||
//
|
||||
// Find the index of the least significant bit within that limb:
|
||||
//
|
||||
unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
|
||||
|
||||
return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the location of the most-significant-bit:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
//
|
||||
// Find the index of the most significant bit that is non-zero:
|
||||
//
|
||||
return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
return eval_msb_imp(a);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
|
||||
eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
return false;
|
||||
return val.limbs()[offset] & mask ? true : false;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
{
|
||||
unsigned os = val.size();
|
||||
val.resize(offset + 1, offset + 1);
|
||||
if(offset >= val.size())
|
||||
return; // fixed precision overflow
|
||||
for(unsigned i = os; i <= offset; ++i)
|
||||
val.limbs()[i] = 0;
|
||||
}
|
||||
val.limbs()[offset] |= mask;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
return;
|
||||
val.limbs()[offset] &= ~mask;
|
||||
val.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
{
|
||||
unsigned os = val.size();
|
||||
val.resize(offset + 1, offset + 1);
|
||||
if(offset >= val.size())
|
||||
return; // fixed precision overflow
|
||||
for(unsigned i = os; i <= offset; ++i)
|
||||
val.limbs()[i] = 0;
|
||||
}
|
||||
val.limbs()[offset] ^= mask;
|
||||
val.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_qr(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
divide_unsigned_helper(&q, x, y, r);
|
||||
q.sign(x.sign() != y.sign());
|
||||
r.sign(x.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_qr(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
||||
limb_type y,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
divide_unsigned_helper(&q, x, y, r);
|
||||
q.sign(x.sign());
|
||||
r.sign(x.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
|
||||
inline typename enable_if_c<is_integral<U>::value>::type eval_qr(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
||||
U y,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
using default_ops::eval_qr;
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
|
||||
t = y;
|
||||
eval_qr(x, t, q, r);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
inline typename enable_if_c<is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
|
||||
eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
|
||||
{
|
||||
if((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits<limb_type>::max)()))
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> d;
|
||||
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>*>(0), x, static_cast<limb_type>(val), d);
|
||||
return d.limbs()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return default_ops::eval_integer_modulus(x, val);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
|
||||
eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
|
||||
{
|
||||
return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
|
||||
}
|
||||
|
||||
inline limb_type integer_gcd_reduce(limb_type u, limb_type v)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(u > v)
|
||||
std::swap(u, v);
|
||||
if(u == v)
|
||||
break;
|
||||
v -= u;
|
||||
v >>= boost::multiprecision::detail::find_lsb(v);
|
||||
} while(true);
|
||||
return u;
|
||||
}
|
||||
|
||||
inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(u > v)
|
||||
std::swap(u, v);
|
||||
if(u == v)
|
||||
break;
|
||||
if(v <= ~static_cast<limb_type>(0))
|
||||
{
|
||||
u = integer_gcd_reduce(static_cast<limb_type>(v), static_cast<limb_type>(u));
|
||||
break;
|
||||
}
|
||||
v -= u;
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
while((v & 1u) == 0)
|
||||
#else
|
||||
while((static_cast<unsigned>(v) & 1u) == 0)
|
||||
#endif
|
||||
v >>= 1;
|
||||
} while(true);
|
||||
return u;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
limb_type v)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
int shift;
|
||||
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a);
|
||||
|
||||
int s = eval_get_sign(u);
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if(s < 0)
|
||||
{
|
||||
u.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
if(v == 0)
|
||||
{
|
||||
result = u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
|
||||
unsigned us = eval_lsb(u);
|
||||
unsigned vs = boost::multiprecision::detail::find_lsb(v);
|
||||
shift = (std::min)(us, vs);
|
||||
eval_right_shift(u, us);
|
||||
if(vs)
|
||||
v >>= vs;
|
||||
|
||||
do
|
||||
{
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
if(u.size() <= 2)
|
||||
{
|
||||
if(u.size() == 1)
|
||||
v = integer_gcd_reduce(*u.limbs(), v);
|
||||
else
|
||||
{
|
||||
double_limb_type i;
|
||||
i = u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
||||
v = static_cast<limb_type>(integer_gcd_reduce(i, static_cast<double_limb_type>(v)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
eval_subtract(u, v);
|
||||
us = eval_lsb(u);
|
||||
eval_right_shift(u, us);
|
||||
}
|
||||
while(true);
|
||||
|
||||
result = v;
|
||||
eval_left_shift(result, shift);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
inline typename enable_if_c<is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const Integer& v)
|
||||
{
|
||||
eval_gcd(result, a, static_cast<limb_type>(v));
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
inline typename enable_if_c<is_signed<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const Integer& v)
|
||||
{
|
||||
eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
if(a.size() == 1)
|
||||
{
|
||||
eval_gcd(result, b, *a.limbs());
|
||||
return;
|
||||
}
|
||||
if(b.size() == 1)
|
||||
{
|
||||
eval_gcd(result, a, *b.limbs());
|
||||
return;
|
||||
}
|
||||
|
||||
int shift;
|
||||
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a), v(b);
|
||||
|
||||
int s = eval_get_sign(u);
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if(s < 0)
|
||||
{
|
||||
u.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
s = eval_get_sign(v);
|
||||
if(s < 0)
|
||||
{
|
||||
v.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
|
||||
unsigned us = eval_lsb(u);
|
||||
unsigned vs = eval_lsb(v);
|
||||
shift = (std::min)(us, vs);
|
||||
eval_right_shift(u, us);
|
||||
eval_right_shift(v, vs);
|
||||
|
||||
do
|
||||
{
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
s = u.compare(v);
|
||||
if(s > 0)
|
||||
u.swap(v);
|
||||
if(s == 0)
|
||||
break;
|
||||
if(v.size() <= 2)
|
||||
{
|
||||
if(v.size() == 1)
|
||||
u = integer_gcd_reduce(*v.limbs(), *u.limbs());
|
||||
else
|
||||
{
|
||||
double_limb_type i, j;
|
||||
i = v.limbs()[0] | (static_cast<double_limb_type>(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
||||
j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
||||
u = integer_gcd_reduce(i, j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
eval_subtract(v, u);
|
||||
vs = eval_lsb(v);
|
||||
eval_right_shift(v, vs);
|
||||
}
|
||||
while(true);
|
||||
|
||||
result = u;
|
||||
eval_left_shift(result, shift);
|
||||
}
|
||||
//
|
||||
// Now again for trivial backends:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
*result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs());
|
||||
}
|
||||
// This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version:
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
|
||||
eval_lcm(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs());
|
||||
result.normalize(); // result may overflow the specified number of bits
|
||||
}
|
||||
|
||||
inline void conversion_overflow(const mpl::int_<checked>&)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
|
||||
}
|
||||
inline void conversion_overflow(const mpl::int_<unchecked>&){}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value
|
||||
>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
|
||||
{
|
||||
typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
|
||||
if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
|
||||
{
|
||||
if(val.isneg())
|
||||
{
|
||||
check_is_negative(mpl::bool_<boost::is_signed<R>::value || (number_category<R>::value == number_kind_floating_point)>());
|
||||
if(static_cast<common_type>(*val.limbs()) > -static_cast<common_type>((std::numeric_limits<R>::min)()))
|
||||
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result = (std::numeric_limits<R>::min)();
|
||||
}
|
||||
else
|
||||
{
|
||||
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result = boost::is_signed<R>::value ? (std::numeric_limits<R>::max)() : static_cast<R>(*val.limbs());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = static_cast<R>(*val.limbs());
|
||||
if(val.isneg())
|
||||
{
|
||||
check_is_negative(mpl::bool_<boost::is_signed<R>::value || (number_category<R>::value == number_kind_floating_point)>());
|
||||
*result = negate_integer(*result, mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value
|
||||
>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
|
||||
{
|
||||
typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
|
||||
if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
|
||||
{
|
||||
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result = boost::is_signed<R>::value ? (std::numeric_limits<R>::max)() : static_cast<R>(*val.limbs());
|
||||
}
|
||||
else
|
||||
*result = static_cast<R>(*val.limbs());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
//
|
||||
// Find the index of the least significant bit within that limb:
|
||||
//
|
||||
return boost::multiprecision::detail::find_lsb(*a.limbs());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
//
|
||||
// Find the index of the least significant bit within that limb:
|
||||
//
|
||||
return boost::multiprecision::detail::find_msb(*a.limbs());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
return eval_msb_imp(a);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline std::size_t hash_value(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t result = 0;
|
||||
for(unsigned i = 0; i < val.size(); ++i)
|
||||
{
|
||||
boost::hash_combine(result, val.limbs()[i]);
|
||||
}
|
||||
boost::hash_combine(result, val.sign());
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,498 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_MUL_HPP
|
||||
#define BOOST_MP_CPP_INT_MUL_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(!val)
|
||||
{
|
||||
result = static_cast<limb_type>(0);
|
||||
return;
|
||||
}
|
||||
if((void*)&a != (void*)&result)
|
||||
result.resize(a.size(), a.size());
|
||||
double_limb_type carry = 0;
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
|
||||
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
|
||||
while(p != pe)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
*p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
*p = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
++p, ++pa;
|
||||
}
|
||||
if(carry)
|
||||
{
|
||||
unsigned i = result.size();
|
||||
result.resize(i + 1, i + 1);
|
||||
if(result.size() > i)
|
||||
result.limbs()[i] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.sign(a.sign());
|
||||
if(!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable)
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
//
|
||||
// resize_for_carry forces a resize of the underlying buffer only if a previous request
|
||||
// for "required" elements could possibly have failed, *and* we have checking enabled.
|
||||
// This will cause an overflow error inside resize():
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/){}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, class Allocator1>
|
||||
inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, Allocator1>& result, unsigned required)
|
||||
{
|
||||
if(result.size() < required)
|
||||
result.resize(required, required);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
// Very simple long multiplication, only usable for small numbers of limb_type's
|
||||
// but that's the typical use case for this type anyway:
|
||||
//
|
||||
// Special cases first:
|
||||
//
|
||||
unsigned as = a.size();
|
||||
unsigned bs = b.size();
|
||||
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
|
||||
typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
|
||||
if(as == 1)
|
||||
{
|
||||
bool s = b.sign() != a.sign();
|
||||
if(bs == 1)
|
||||
{
|
||||
result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
|
||||
}
|
||||
else
|
||||
{
|
||||
limb_type l = *pa;
|
||||
eval_multiply(result, b, l);
|
||||
}
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
if(bs == 1)
|
||||
{
|
||||
bool s = b.sign() != a.sign();
|
||||
limb_type l = *pb;
|
||||
eval_multiply(result, a, l);
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if((void*)&result == (void*)&a)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
|
||||
eval_multiply(result, t, b);
|
||||
return;
|
||||
}
|
||||
if((void*)&result == (void*)&b)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
|
||||
eval_multiply(result, a, t);
|
||||
return;
|
||||
}
|
||||
|
||||
result.resize(as + bs, as + bs - 1);
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
|
||||
|
||||
static const double_limb_type limb_max = ~static_cast<limb_type>(0u);
|
||||
static const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u);
|
||||
BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max);
|
||||
|
||||
double_limb_type carry = 0;
|
||||
std::memset(pr, 0, result.size() * sizeof(limb_type));
|
||||
for(unsigned i = 0; i < as; ++i)
|
||||
{
|
||||
unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
|
||||
unsigned j;
|
||||
for(j = 0; j < inner_limit; ++j)
|
||||
{
|
||||
BOOST_ASSERT(i+j < result.size());
|
||||
#if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
|
||||
BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized
|
||||
|| ((std::numeric_limits<double_limb_type>::max)() - carry
|
||||
>
|
||||
static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value) * static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value)));
|
||||
#endif
|
||||
carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
|
||||
BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j]));
|
||||
carry += pr[i + j];
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
pr[i + j] = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
|
||||
}
|
||||
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;
|
||||
}
|
||||
result.normalize();
|
||||
//
|
||||
// Set the sign of the result:
|
||||
//
|
||||
result.sign(a.sign() != b.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, a);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(val <= (std::numeric_limits<limb_type>::max)())
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
|
||||
#else
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
|
||||
t = val;
|
||||
#endif
|
||||
eval_multiply(result, a, t);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(val > 0)
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
else
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
|
||||
result.negate();
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(val > 0)
|
||||
{
|
||||
if(val <= (std::numeric_limits<limb_type>::max)())
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
|
||||
#else
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
|
||||
t = val;
|
||||
#endif
|
||||
eval_multiply(result, a, t);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
//
|
||||
// Now over again for trivial cpp_int's:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.sign(result.sign() != o.sign());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.sign(a.sign() != b.sign());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
//
|
||||
// Special routines for multiplying two integers to obtain a multiprecision result:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
signed_double_limb_type a, signed_double_limb_type b)
|
||||
{
|
||||
static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
|
||||
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
bool s = false;
|
||||
double_limb_type w, x, y, z;
|
||||
if(a < 0)
|
||||
{
|
||||
a = -a;
|
||||
s = true;
|
||||
}
|
||||
if(b < 0)
|
||||
{
|
||||
b = -b;
|
||||
s = !s;
|
||||
}
|
||||
w = a & mask;
|
||||
x = a >> limb_bits;
|
||||
y = b & mask;
|
||||
z = b >> limb_bits;
|
||||
|
||||
result.resize(4, 4);
|
||||
limb_type* pr = result.limbs();
|
||||
|
||||
double_limb_type carry = w * y;
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += w * z + x * y;
|
||||
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += x * z;
|
||||
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#else
|
||||
pr[0] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += w * z + x * y;
|
||||
pr[1] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += x * z;
|
||||
pr[2] = static_cast<limb_type>(carry);
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#endif
|
||||
result.sign(s);
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
double_limb_type a, double_limb_type b)
|
||||
{
|
||||
static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
|
||||
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
|
||||
double_limb_type w, x, y, z;
|
||||
w = a & mask;
|
||||
x = a >> limb_bits;
|
||||
y = b & mask;
|
||||
z = b >> limb_bits;
|
||||
|
||||
result.resize(4, 4);
|
||||
limb_type* pr = result.limbs();
|
||||
|
||||
double_limb_type carry = w * y;
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += w * z;
|
||||
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry = x * y + pr[1];
|
||||
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += pr[2] + x * z;
|
||||
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#else
|
||||
pr[0] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += w * z;
|
||||
pr[1] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
pr[2] = static_cast<limb_type>(carry);
|
||||
carry = x * y + pr[1];
|
||||
pr[1] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += pr[2] + x * z;
|
||||
pr[2] = static_cast<limb_type>(carry);
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#endif
|
||||
result.sign(false);
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
|
||||
unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
|
||||
cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::local_limb_type, cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::type canonical_type;
|
||||
eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
|
||||
result.sign(a.sign() != b.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
SI a, SI b)
|
||||
{
|
||||
result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
UI a, UI b)
|
||||
{
|
||||
result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,199 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_SERIALIZE_HPP
|
||||
#define BOOST_MP_CPP_INT_SERIALIZE_HPP
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace archive{
|
||||
|
||||
class binary_oarchive;
|
||||
class binary_iarchive;
|
||||
|
||||
}
|
||||
|
||||
namespace serialization {
|
||||
|
||||
namespace mp = boost::multiprecision;
|
||||
|
||||
namespace cpp_int_detail{
|
||||
|
||||
using namespace boost::multiprecision;
|
||||
using namespace boost::multiprecision::backends;
|
||||
|
||||
template <class T>
|
||||
struct is_binary_archive : public mpl::false_ {};
|
||||
template <>
|
||||
struct is_binary_archive<boost::archive::binary_oarchive> : public mpl::true_ {};
|
||||
template <>
|
||||
struct is_binary_archive<boost::archive::binary_iarchive> : public mpl::true_ {};
|
||||
|
||||
//
|
||||
// We have 8 serialization methods to fill out (and test), they are all permutations of:
|
||||
// Load vs Store.
|
||||
// Trivial or non-trivial cpp_int type.
|
||||
// Binary or not archive.
|
||||
//
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, mpl::false_ const&)
|
||||
{
|
||||
// Load.
|
||||
// Non-trivial.
|
||||
// Non binary.
|
||||
|
||||
bool s;
|
||||
ar & s;
|
||||
std::size_t limb_count;
|
||||
std::size_t byte_count;
|
||||
ar & byte_count;
|
||||
limb_count = byte_count / sizeof(limb_type) + ((byte_count % sizeof(limb_type)) ? 1 : 0);
|
||||
val.resize(limb_count, limb_count);
|
||||
limb_type* pl = val.limbs();
|
||||
for(std::size_t i = 0; i < limb_count; ++i)
|
||||
{
|
||||
pl[i] = 0;
|
||||
for(std::size_t j = 0; (j < sizeof(limb_type)) && byte_count; ++j)
|
||||
{
|
||||
unsigned char byte;
|
||||
ar & byte;
|
||||
pl[i] |= static_cast<limb_type>(byte) << (j * CHAR_BIT);
|
||||
--byte_count;
|
||||
}
|
||||
}
|
||||
if(s != val.sign())
|
||||
val.negate();
|
||||
val.normalize();
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, mpl::false_ const&)
|
||||
{
|
||||
// Store.
|
||||
// Non-trivial.
|
||||
// Non binary.
|
||||
|
||||
bool s = val.sign();
|
||||
ar & s;
|
||||
limb_type* pl = val.limbs();
|
||||
std::size_t limb_count = val.size();
|
||||
std::size_t byte_count = limb_count * sizeof(limb_type);
|
||||
ar & byte_count;
|
||||
|
||||
for(std::size_t i = 0; i < limb_count; ++i)
|
||||
{
|
||||
limb_type l = pl[i];
|
||||
for(std::size_t j = 0; j < sizeof(limb_type); ++j)
|
||||
{
|
||||
unsigned char byte = static_cast<unsigned char>((l >> (j * CHAR_BIT)) & ((1u << CHAR_BIT) - 1));
|
||||
ar & byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, mpl::false_ const&)
|
||||
{
|
||||
// Load.
|
||||
// Trivial.
|
||||
// Non binary.
|
||||
bool s;
|
||||
typename Int::local_limb_type l = 0;
|
||||
ar & s;
|
||||
std::size_t byte_count;
|
||||
ar & byte_count;
|
||||
for(std::size_t i = 0; i < byte_count; ++i)
|
||||
{
|
||||
unsigned char b;
|
||||
ar & b;
|
||||
l |= static_cast<typename Int::local_limb_type>(b) << (i * CHAR_BIT);
|
||||
}
|
||||
*val.limbs() = l;
|
||||
if(s != val.sign())
|
||||
val.negate();
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, mpl::false_ const&)
|
||||
{
|
||||
// Store.
|
||||
// Trivial.
|
||||
// Non binary.
|
||||
bool s = val.sign();
|
||||
typename Int::local_limb_type l = *val.limbs();
|
||||
ar & s;
|
||||
std::size_t limb_count = sizeof(l);
|
||||
ar & limb_count;
|
||||
for(std::size_t i = 0; i < limb_count; ++i)
|
||||
{
|
||||
unsigned char b = static_cast<unsigned char>(static_cast<typename Int::local_limb_type>(l >> (i * CHAR_BIT)) & static_cast<typename Int::local_limb_type>((1u << CHAR_BIT) - 1));
|
||||
ar & b;
|
||||
}
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::false_ const&, mpl::true_ const&)
|
||||
{
|
||||
// Load.
|
||||
// Non-trivial.
|
||||
// Binary.
|
||||
bool s;
|
||||
std::size_t c;
|
||||
ar & s;
|
||||
ar & c;
|
||||
val.resize(c, c);
|
||||
ar.load_binary(val.limbs(), c * sizeof(limb_type));
|
||||
if(s != val.sign())
|
||||
val.negate();
|
||||
val.normalize();
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::false_ const&, mpl::true_ const&)
|
||||
{
|
||||
// Store.
|
||||
// Non-trivial.
|
||||
// Binary.
|
||||
bool s = val.sign();
|
||||
std::size_t c = val.size();
|
||||
ar & s;
|
||||
ar & c;
|
||||
ar.save_binary(val.limbs(), c * sizeof(limb_type));
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::false_ const&, mpl::true_ const&, mpl::true_ const&)
|
||||
{
|
||||
// Load.
|
||||
// Trivial.
|
||||
// Binary.
|
||||
bool s;
|
||||
ar & s;
|
||||
ar.load_binary(val.limbs(), sizeof(*val.limbs()));
|
||||
if(s != val.sign())
|
||||
val.negate();
|
||||
}
|
||||
template <class Archive, class Int>
|
||||
void do_serialize(Archive& ar, Int& val, mpl::true_ const&, mpl::true_ const&, mpl::true_ const&)
|
||||
{
|
||||
// Store.
|
||||
// Trivial.
|
||||
// Binary.
|
||||
bool s = val.sign();
|
||||
ar & s;
|
||||
ar.save_binary(val.limbs(), sizeof(*val.limbs()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<class Archive, unsigned MinBits, unsigned MaxBits, mp::cpp_integer_type SignType, mp::cpp_int_check_type Checked, class Allocator>
|
||||
void serialize(Archive & ar, mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& val, const unsigned int /*version*/)
|
||||
{
|
||||
typedef typename Archive::is_saving save_tag;
|
||||
typedef mpl::bool_<mp::backends::is_trivial_cpp_int<mp::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value> trivial_tag;
|
||||
typedef typename cpp_int_detail::is_binary_archive<Archive>::type binary_tag;
|
||||
|
||||
// Just dispatch to the correct method:
|
||||
cpp_int_detail::do_serialize(ar, val, save_tag(), trivial_tag(), binary_tag());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_SERIALIZE_HPP
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_VP_HPP
|
||||
#define BOOST_MP_CPP_INT_VP_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace literals{ namespace detail{
|
||||
|
||||
template <limb_type...VALUES>
|
||||
struct value_pack
|
||||
{
|
||||
constexpr value_pack(){}
|
||||
|
||||
typedef value_pack<0, VALUES...> next_type;
|
||||
};
|
||||
template <class T>
|
||||
struct is_value_pack{ static constexpr bool value = false; };
|
||||
template <limb_type...VALUES>
|
||||
struct is_value_pack<value_pack<VALUES...> >{ static constexpr bool value = true; };
|
||||
|
||||
struct negate_tag{};
|
||||
|
||||
constexpr negate_tag make_negate_tag()
|
||||
{
|
||||
return negate_tag();
|
||||
}
|
||||
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
#endif // BOOST_MP_CPP_INT_CORE_HPP
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MATH_DEBUG_ADAPTER_HPP
|
||||
#define BOOST_MATH_DEBUG_ADAPTER_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/extract_exponent_type.hpp>
|
||||
#include <boost/multiprecision/detail/integer_ops.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace backends{
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
template <class Backend>
|
||||
struct debug_adaptor
|
||||
{
|
||||
typedef typename Backend::signed_types signed_types;
|
||||
typedef typename Backend::unsigned_types unsigned_types;
|
||||
typedef typename Backend::float_types float_types;
|
||||
typedef typename extract_exponent_type<
|
||||
Backend, number_category<Backend>::value>::type exponent_type;
|
||||
|
||||
private:
|
||||
std::string debug_value;
|
||||
Backend m_value;
|
||||
public:
|
||||
void update_view()
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
debug_value = m_value.str(0, static_cast<std::ios_base::fmtflags>(0));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
debug_value = "String conversion failed with message: \"";
|
||||
debug_value += e.what();
|
||||
debug_value += "\"";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
debug_adaptor()
|
||||
{
|
||||
update_view();
|
||||
}
|
||||
debug_adaptor(const debug_adaptor& o) : debug_value(o.debug_value), m_value(o.m_value)
|
||||
{
|
||||
}
|
||||
debug_adaptor& operator = (const debug_adaptor& o)
|
||||
{
|
||||
debug_value = o.debug_value;
|
||||
m_value = o.m_value;
|
||||
return *this;
|
||||
}
|
||||
template <class T>
|
||||
debug_adaptor(const T& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
|
||||
: m_value(i)
|
||||
{
|
||||
update_view();
|
||||
}
|
||||
template <class T>
|
||||
debug_adaptor(const T& i, const T& j)
|
||||
: m_value(i, j)
|
||||
{
|
||||
update_view();
|
||||
}
|
||||
template <class T>
|
||||
typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, Backend>::value, debug_adaptor&>::type operator = (const T& i)
|
||||
{
|
||||
m_value = i;
|
||||
update_view();
|
||||
return *this;
|
||||
}
|
||||
debug_adaptor& operator = (const char* s)
|
||||
{
|
||||
m_value = s;
|
||||
update_view();
|
||||
return *this;
|
||||
}
|
||||
void swap(debug_adaptor& o)
|
||||
{
|
||||
std::swap(m_value, o.value());
|
||||
std::swap(debug_value, o.debug_value);
|
||||
}
|
||||
std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
|
||||
{
|
||||
return m_value.str(digits, f);
|
||||
}
|
||||
void negate()
|
||||
{
|
||||
m_value.negate();
|
||||
update_view();
|
||||
}
|
||||
int compare(const debug_adaptor& o)const
|
||||
{
|
||||
return m_value.compare(o.value());
|
||||
}
|
||||
template <class T>
|
||||
int compare(const T& i)const
|
||||
{
|
||||
return m_value.compare(i);
|
||||
}
|
||||
Backend& value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
const Backend& value()const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /*version*/)
|
||||
{
|
||||
ar & m_value;
|
||||
typedef typename Archive::is_loading tag;
|
||||
if(tag::value)
|
||||
update_view();
|
||||
}
|
||||
static unsigned default_precision() BOOST_NOEXCEPT
|
||||
{
|
||||
return Backend::default_precision();
|
||||
}
|
||||
static void default_precision(unsigned v) BOOST_NOEXCEPT
|
||||
{
|
||||
Backend::default_precision(v);
|
||||
}
|
||||
unsigned precision()const BOOST_NOEXCEPT
|
||||
{
|
||||
return value().precision();
|
||||
}
|
||||
void precision(unsigned digits10) BOOST_NOEXCEPT
|
||||
{
|
||||
value().precision(digits10);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Backend>
|
||||
inline Backend const& unwrap_debug_type(debug_adaptor<Backend> const& val)
|
||||
{
|
||||
return val.value();
|
||||
}
|
||||
template <class T>
|
||||
inline const T& unwrap_debug_type(const T& val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP1(name, str) \
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value());\
|
||||
result.update_view();\
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP2(name, str) \
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a));\
|
||||
result.update_view();\
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP3(name, str) \
|
||||
template <class Backend, class T, class U>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const U& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const T& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const debug_adaptor<Backend>& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const debug_adaptor<Backend>& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
|
||||
result.update_view();\
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP4(name, str) \
|
||||
template <class Backend, class T, class U, class V>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const U& b, const V& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const debug_adaptor<Backend>& b, const T& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const T& b, const debug_adaptor<Backend>& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const debug_adaptor<Backend>& b, const debug_adaptor<Backend>& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const debug_adaptor<Backend>& b, const debug_adaptor<Backend>& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
|
||||
result.update_view();\
|
||||
}\
|
||||
template <class Backend, class T, class U>\
|
||||
inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const T& b, const U& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
|
||||
result.update_view();\
|
||||
}\
|
||||
|
||||
NON_MEMBER_OP2(add, "+=")
|
||||
NON_MEMBER_OP2(subtract, "-=")
|
||||
NON_MEMBER_OP2(multiply, "*=")
|
||||
NON_MEMBER_OP2(divide, "/=")
|
||||
|
||||
template <class Backend, class R>
|
||||
inline void eval_convert_to(R* result, const debug_adaptor<Backend>& val)
|
||||
{
|
||||
using default_ops::eval_convert_to;
|
||||
eval_convert_to(result, val.value());
|
||||
}
|
||||
|
||||
template <class Backend, class Exp>
|
||||
inline void eval_frexp(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& arg, Exp* exp)
|
||||
{
|
||||
eval_frexp(result.value(), arg.value(), exp);
|
||||
result.update_view();
|
||||
}
|
||||
|
||||
template <class Backend, class Exp>
|
||||
inline void eval_ldexp(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& arg, Exp exp)
|
||||
{
|
||||
eval_ldexp(result.value(), arg.value(), exp);
|
||||
result.update_view();
|
||||
}
|
||||
|
||||
template <class Backend, class Exp>
|
||||
inline void eval_scalbn(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& arg, Exp exp)
|
||||
{
|
||||
using default_ops::eval_scalbn;
|
||||
eval_scalbn(result.value(), arg.value(), exp);
|
||||
result.update_view();
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline typename Backend::exponent_type eval_ilogb(const debug_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_ilogb;
|
||||
return eval_ilogb(arg.value());
|
||||
}
|
||||
|
||||
NON_MEMBER_OP2(floor, "floor")
|
||||
NON_MEMBER_OP2(ceil, "ceil")
|
||||
NON_MEMBER_OP2(sqrt, "sqrt")
|
||||
NON_MEMBER_OP2(logb, "logb")
|
||||
|
||||
template <class Backend>
|
||||
inline int eval_fpclassify(const debug_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_fpclassify;
|
||||
return eval_fpclassify(arg.value());
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Optional arithmetic operations come next:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP3(add, "+")
|
||||
NON_MEMBER_OP3(subtract, "-")
|
||||
NON_MEMBER_OP3(multiply, "*")
|
||||
NON_MEMBER_OP3(divide, "/")
|
||||
NON_MEMBER_OP3(multiply_add, "fused-multiply-add")
|
||||
NON_MEMBER_OP3(multiply_subtract, "fused-multiply-subtract")
|
||||
NON_MEMBER_OP4(multiply_add, "fused-multiply-add")
|
||||
NON_MEMBER_OP4(multiply_subtract, "fused-multiply-subtract")
|
||||
|
||||
NON_MEMBER_OP1(increment, "increment")
|
||||
NON_MEMBER_OP1(decrement, "decrement")
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Optional integer operations come next:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP2(modulus, "%=")
|
||||
NON_MEMBER_OP3(modulus, "%")
|
||||
NON_MEMBER_OP2(bitwise_or, "|=")
|
||||
NON_MEMBER_OP3(bitwise_or, "|")
|
||||
NON_MEMBER_OP2(bitwise_and, "&=")
|
||||
NON_MEMBER_OP3(bitwise_and, "&")
|
||||
NON_MEMBER_OP2(bitwise_xor, "^=")
|
||||
NON_MEMBER_OP3(bitwise_xor, "^")
|
||||
NON_MEMBER_OP4(qr, "quotient-and-remainder")
|
||||
NON_MEMBER_OP2(complement, "~")
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_left_shift(debug_adaptor<Backend>& arg, std::size_t a)
|
||||
{
|
||||
using default_ops::eval_left_shift;
|
||||
eval_left_shift(arg.value(), a);
|
||||
arg.update_view();\
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_left_shift(debug_adaptor<Backend>& arg, const debug_adaptor<Backend>& a, std::size_t b)
|
||||
{
|
||||
using default_ops::eval_left_shift;
|
||||
eval_left_shift(arg.value(), a.value(), b);
|
||||
arg.update_view();\
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_right_shift(debug_adaptor<Backend>& arg, std::size_t a)
|
||||
{
|
||||
using default_ops::eval_right_shift;
|
||||
eval_right_shift(arg.value(), a);
|
||||
arg.update_view();\
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_right_shift(debug_adaptor<Backend>& arg, const debug_adaptor<Backend>& a, std::size_t b)
|
||||
{
|
||||
using default_ops::eval_right_shift;
|
||||
eval_right_shift(arg.value(), a.value(), b);
|
||||
arg.update_view();\
|
||||
}
|
||||
|
||||
template <class Backend, class T>
|
||||
inline unsigned eval_integer_modulus(const debug_adaptor<Backend>& arg, const T& a)
|
||||
{
|
||||
using default_ops::eval_integer_modulus;
|
||||
return eval_integer_modulus(arg.value(), a);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline unsigned eval_lsb(const debug_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
return eval_lsb(arg.value());
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline unsigned eval_msb(const debug_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_msb;
|
||||
return eval_msb(arg.value());
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline bool eval_bit_test(const debug_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_test;
|
||||
return eval_bit_test(arg.value(), a);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_bit_set(const debug_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_set;
|
||||
eval_bit_set(arg.value(), a);
|
||||
arg.update_view();\
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_bit_unset(const debug_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_unset;
|
||||
eval_bit_unset(arg.value(), a);
|
||||
arg.update_view();\
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_bit_flip(const debug_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_flip;
|
||||
eval_bit_flip(arg.value(), a);
|
||||
arg.update_view();\
|
||||
}
|
||||
|
||||
NON_MEMBER_OP3(gcd, "gcd")
|
||||
NON_MEMBER_OP3(lcm, "lcm")
|
||||
NON_MEMBER_OP4(powm, "powm");
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* abs/fabs:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP2(abs, "abs")
|
||||
NON_MEMBER_OP2(fabs, "fabs")
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Floating point functions:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP2(trunc, "trunc")
|
||||
NON_MEMBER_OP2(round, "round")
|
||||
NON_MEMBER_OP2(exp, "exp")
|
||||
NON_MEMBER_OP2(log, "log")
|
||||
NON_MEMBER_OP2(log10, "log10")
|
||||
NON_MEMBER_OP2(sin, "sin")
|
||||
NON_MEMBER_OP2(cos, "cos")
|
||||
NON_MEMBER_OP2(tan, "tan")
|
||||
NON_MEMBER_OP2(asin, "asin")
|
||||
NON_MEMBER_OP2(acos, "acos")
|
||||
NON_MEMBER_OP2(atan, "atan")
|
||||
NON_MEMBER_OP2(sinh, "sinh")
|
||||
NON_MEMBER_OP2(cosh, "cosh")
|
||||
NON_MEMBER_OP2(tanh, "tanh")
|
||||
NON_MEMBER_OP3(fmod, "fmod")
|
||||
NON_MEMBER_OP3(pow, "pow")
|
||||
NON_MEMBER_OP3(atan2, "atan2")
|
||||
|
||||
template <class Backend>
|
||||
int eval_signbit(const debug_adaptor<Backend>& val)
|
||||
{
|
||||
return eval_signbit(val.value());
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
std::size_t hash_value(const debug_adaptor<Backend>& val)
|
||||
{
|
||||
return hash_value(val.value());
|
||||
}
|
||||
|
||||
} // namespace backends
|
||||
|
||||
using backends::debug_adaptor;
|
||||
|
||||
template<class Backend>
|
||||
struct number_category<backends::debug_adaptor<Backend> > : public number_category<Backend> {};
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}} // namespaces
|
||||
|
||||
namespace std{
|
||||
|
||||
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::debug_adaptor<Backend>, ExpressionTemplates> >
|
||||
: public std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> >
|
||||
{
|
||||
typedef std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> > base_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::backends::debug_adaptor<Backend>, ExpressionTemplates> number_type;
|
||||
public:
|
||||
static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
|
||||
static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
|
||||
static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
|
||||
static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
|
||||
static number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
|
||||
static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
|
||||
static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
|
||||
static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
|
||||
static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace policies{
|
||||
|
||||
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
|
||||
struct precision< boost::multiprecision::number<boost::multiprecision::debug_adaptor<Backend>, ExpressionTemplates>, Policy>
|
||||
: public precision<boost::multiprecision::number<Backend, ExpressionTemplates>, Policy>
|
||||
{};
|
||||
|
||||
#undef NON_MEMBER_OP1
|
||||
#undef NON_MEMBER_OP2
|
||||
#undef NON_MEMBER_OP3
|
||||
#undef NON_MEMBER_OP4
|
||||
|
||||
} // namespace policies
|
||||
|
||||
}} // namespaces boost::math
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
// Copyright (c) 2011 John Maddock
|
||||
// Use, modification and distribution are subject to 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_MP_BIG_LANCZOS
|
||||
#define BOOST_MP_BIG_LANCZOS
|
||||
|
||||
#include <boost/math/bindings/detail/big_lanczos.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace lanczos{
|
||||
|
||||
template <class T, class Policy>
|
||||
struct lanczos;
|
||||
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
|
||||
struct lanczos<multiprecision::number<Backend, ExpressionTemplates>, Policy>
|
||||
{
|
||||
typedef typename boost::math::policies::precision<multiprecision::number<Backend, ExpressionTemplates>, Policy>::type precision_type;
|
||||
typedef typename mpl::if_c<
|
||||
precision_type::value && (precision_type::value <= 73),
|
||||
lanczos13UDT,
|
||||
typename mpl::if_c<
|
||||
precision_type::value&& (precision_type::value <= 122),
|
||||
lanczos22UDT,
|
||||
undefined_lanczos
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
} // namespace lanczos
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_DETAIL_BITSCAN_HPP
|
||||
#define BOOST_MP_DETAIL_BITSCAN_HPP
|
||||
|
||||
#include <boost/detail/endian.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
template <class Unsigned>
|
||||
inline unsigned find_lsb(Unsigned mask, const mpl::int_<0>&)
|
||||
{
|
||||
unsigned result = 0;
|
||||
while(!(mask & 1u))
|
||||
{
|
||||
mask >>= 1;
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Unsigned>
|
||||
inline unsigned find_msb(Unsigned mask, const mpl::int_<0>&)
|
||||
{
|
||||
unsigned index = 0;
|
||||
while(mask)
|
||||
{
|
||||
++index;
|
||||
mask >>= 1;
|
||||
}
|
||||
return --index;
|
||||
}
|
||||
|
||||
#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
|
||||
|
||||
#pragma intrinsic(_BitScanForward,_BitScanReverse)
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, const mpl::int_<1>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanForward(&result, mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, const mpl::int_<1>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanReverse(&result, mask);
|
||||
return result;
|
||||
}
|
||||
#ifdef _M_X64
|
||||
|
||||
#pragma intrinsic(_BitScanForward64,_BitScanReverse64)
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned __int64 mask, const mpl::int_<2>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanForward64(&result, mask);
|
||||
return result;
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask, const mpl::int_<2>&)
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanReverse64(&result, mask);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<1>,
|
||||
#ifdef _M_X64
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(__int64),
|
||||
mpl::int_<2>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
#else
|
||||
mpl::int_<0>
|
||||
#endif
|
||||
>::type tag_type;
|
||||
return find_lsb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<1>,
|
||||
#ifdef _M_X64
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(__int64),
|
||||
mpl::int_<2>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
#else
|
||||
mpl::int_<0>
|
||||
#endif
|
||||
>::type tag_type;
|
||||
return find_msb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
|
||||
#elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return __builtin_ctz(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, mpl::int_<2> const&)
|
||||
{
|
||||
return __builtin_ctzl(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_lsb(boost::ulong_long_type mask, mpl::int_<3> const&)
|
||||
{
|
||||
return __builtin_ctzll(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return sizeof(unsigned) * CHAR_BIT - 1 - __builtin_clz(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, mpl::int_<2> const&)
|
||||
{
|
||||
return sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(boost::ulong_long_type mask, mpl::int_<3> const&)
|
||||
{
|
||||
return sizeof(boost::ulong_long_type) * CHAR_BIT - 1 - __builtin_clzll(mask);
|
||||
}
|
||||
#ifdef BOOST_HAS_INT128
|
||||
|
||||
__extension__ typedef unsigned __int128 uint128_type;
|
||||
|
||||
BOOST_FORCEINLINE unsigned find_msb(uint128_type mask, mpl::int_<0> const&)
|
||||
{
|
||||
union { uint128_type v; boost::uint64_t sv[2]; } val;
|
||||
val.v = mask;
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
if(val.sv[1])
|
||||
return find_msb(val.sv[1], mpl::int_<3>()) + 64;
|
||||
return find_msb(val.sv[0], mpl::int_<3>());
|
||||
#else
|
||||
if(val.sv[0])
|
||||
return find_msb(val.sv[0], mpl::int_<3>()) + 64;
|
||||
return find_msb(val.sv[1], mpl::int_<3>());
|
||||
#endif
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_lsb(uint128_type mask, mpl::int_<0> const&)
|
||||
{
|
||||
union { uint128_type v; boost::uint64_t sv[2]; } val;
|
||||
val.v = mask;
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
if(val.sv[0] == 0)
|
||||
return find_lsb(val.sv[1], mpl::int_<3>()) + 64;
|
||||
return find_lsb(val.sv[0], mpl::int_<3>());
|
||||
#else
|
||||
if(val.sv[1] == 0)
|
||||
return find_lsb(val.sv[0], mpl::int_<3>()) + 64;
|
||||
return find_lsb(val.sv[1], mpl::int_<3>());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<2>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
|
||||
mpl::int_<3>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
return find_lsb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned long),
|
||||
mpl::int_<2>,
|
||||
typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
|
||||
mpl::int_<3>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
return find_msb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
#elif defined(BOOST_INTEL)
|
||||
BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return _bit_scan_forward(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
|
||||
{
|
||||
return _bit_scan_reverse(mask);
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
mpl::int_<0>
|
||||
>::type tag_type;
|
||||
return find_lsb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
typedef typename make_unsigned<Unsigned>::type ui_type;
|
||||
typedef typename mpl::if_c<
|
||||
sizeof(Unsigned) <= sizeof(unsigned),
|
||||
mpl::int_<1>,
|
||||
mpl::int_<0>
|
||||
>::type tag_type;
|
||||
return find_msb(static_cast<ui_type>(mask), tag_type());
|
||||
}
|
||||
#else
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
|
||||
{
|
||||
return find_lsb(mask, mpl::int_<0>());
|
||||
}
|
||||
template <class Unsigned>
|
||||
BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
|
||||
{
|
||||
return find_msb(mask, mpl::int_<0>());
|
||||
}
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_DIGITS_HPP
|
||||
#define BOOST_MP_DIGITS_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
inline unsigned long digits10_2_2(unsigned long d10)
|
||||
{
|
||||
return (d10 * 1000uL) / 301uL + ((d10 * 1000uL) % 301 ? 2u : 1u);
|
||||
}
|
||||
|
||||
inline unsigned long digits2_2_10(unsigned long d2)
|
||||
{
|
||||
return (d2 * 301uL) / 1000uL;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock.
|
||||
// Copyright Christopher Kormanyos 2013. 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_MP_DETAIL_DYNAMIC_ARRAY_HPP
|
||||
#define BOOST_MP_DETAIL_DYNAMIC_ARRAY_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <boost/multiprecision/detail/rebind.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace detail
|
||||
{
|
||||
template <class value_type, const boost::uint32_t elem_number, class my_allocator>
|
||||
struct dynamic_array : public std::vector<value_type, typename rebind<value_type, my_allocator>::type>
|
||||
{
|
||||
dynamic_array() :
|
||||
std::vector<value_type, typename rebind<value_type, my_allocator>::type>(static_cast<typename std::vector<value_type, typename rebind<value_type, my_allocator>::type>::size_type>(elem_number), static_cast<value_type>(0))
|
||||
{
|
||||
}
|
||||
|
||||
value_type* data() { return &(*(this->begin())); }
|
||||
const value_type* data() const { return &(*(this->begin())); }
|
||||
};
|
||||
} } } } // namespace boost::multiprecision::backends::detail
|
||||
|
||||
#endif // BOOST_MP_DETAIL_DYNAMIC_ARRAY_HPP
|
||||
@@ -0,0 +1,819 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_MP_ET_OPS_HPP
|
||||
#define BOOST_MP_ET_OPS_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
//
|
||||
// Non-member operators for number:
|
||||
//
|
||||
// Unary operators first.
|
||||
// Note that these *must* return by value, even though that's somewhat against
|
||||
// existing practice. The issue is that in C++11 land one could easily and legitimately
|
||||
// write:
|
||||
// auto x = +1234_my_user_defined_suffix;
|
||||
// which would result in a dangling-reference-to-temporary if unary + returned a reference
|
||||
// to it's argument. While return-by-value is obviously inefficient in other situations
|
||||
// the reality is that no one ever uses unary operator+ anyway...!
|
||||
//
|
||||
template <class B, expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CONSTEXPR const number<B, ExpressionTemplates> operator + (const number<B, ExpressionTemplates>& v) { return v; }
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline BOOST_CONSTEXPR const detail::expression<tag, Arg1, Arg2, Arg3, Arg4> operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& v) { return v; }
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, number<B, et_on> > operator - (const number<B, et_on>& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(is_signed_number<B>::value, "Negating an unsigned type results in ill-defined behavior.");
|
||||
return detail::expression<detail::negate, number<B, et_on> >(v);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG((is_signed_number<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value), "Negating an unsigned type results in ill-defined behavior.");
|
||||
return detail::expression<detail::negate, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(v);
|
||||
}
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::complement_immediates, number<B, et_on> > >::type
|
||||
operator ~ (const number<B, et_on>& v) { return detail::expression<detail::complement_immediates, number<B, et_on> >(v); }
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_complement, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator ~ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& v) { return detail::expression<detail::bitwise_complement, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(v); }
|
||||
//
|
||||
// Then addition:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator + (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::add_immediates, number<B, et_on>, V > >::type
|
||||
operator + (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::add_immediates, V, number<B, et_on> > >::type
|
||||
operator + (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::plus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator + (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator + (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::plus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::plus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator + (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Fused multiply add:
|
||||
//
|
||||
template <class V, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >::type
|
||||
operator + (const V& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(b.left(), b.right(), a);
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >::type
|
||||
operator + (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(a.left(), a.right(), b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >
|
||||
operator + (const number<B, ET>& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(b.left(), b.right(), a);
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >
|
||||
operator + (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_add, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(a.left(), a.right(), b);
|
||||
}
|
||||
//
|
||||
// Fused multiply subtract:
|
||||
//
|
||||
template <class V, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> > >::type
|
||||
operator - (const V& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >
|
||||
(detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(b.left(), b.right(), a));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>,
|
||||
detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V> >::type
|
||||
operator - (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, V>(a.left(), a.right(), b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> > >
|
||||
operator - (const number<B, ET>& a, const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> > >
|
||||
(detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(b.left(), b.right(), a));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >
|
||||
operator - (const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_subtract, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::left_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::right_type, number<B, ET> >(a.left(), a.right(), b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::minus, number<B, ET>, Arg1>
|
||||
operator + (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, number<B, ET>, Arg1>(a, b.left_ref());
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::minus, number<B, ET>, Arg1>
|
||||
operator + (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, number<B, ET>, Arg1>(b, a.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator + (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >(b, a.left_ref());
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::subtract_immediates, V, number<B, et_on> > >::type
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, V, number<B, et_on> >(b, a.left_ref());
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> > >::type
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> >(b, a.left_ref());
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> > >::type
|
||||
operator + (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B2, ET>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator + (const detail::expression<detail::negate, number<B, et_on> >& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >(detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(a.left_ref(), b.left_ref()));
|
||||
}
|
||||
//
|
||||
// Subtraction:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator - (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::subtract_immediates, number<B, et_on>, V > >::type
|
||||
operator - (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::subtract_immediates, V, number<B, et_on> > >::type
|
||||
operator - (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::subtract_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::minus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator - (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator - (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::minus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::minus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator - (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::minus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::plus, number<B, ET>, Arg1>
|
||||
operator - (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::plus, number<B, ET>, Arg1>(a, b.left_ref());
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::plus, number<B, ET>, Arg1> >
|
||||
operator - (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::plus, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::plus, number<B, ET>, Arg1>(b, a.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator - (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator - (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::add_immediates, number<B, et_on>, number<B, et_on> >(b, a.left_ref()));
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, V > > >::type
|
||||
operator - (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, V > >(detail::expression<detail::add_immediates, number<B, et_on>, V >(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator - (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::add_immediates, number<B, et_on>, number<B2, ET> > >(detail::expression<detail::add_immediates, number<B, et_on>, number<B2, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::add_immediates, V, number<B, et_on> > >::type
|
||||
operator - (const V& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, V, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::add_immediates, number<B2, ET>, number<B, et_on> > >::type
|
||||
operator - (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::add_immediates, number<B2, ET>, number<B, et_on> >(a, b.left_ref());
|
||||
}
|
||||
//
|
||||
// Multiplication:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator * (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::multiply_immediates, number<B, et_on>, V > >::type
|
||||
operator * (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::multiply_immediates, V, number<B, et_on> > >::type
|
||||
operator * (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::multiply_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::multiplies, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator * (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator * (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator * (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator * (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::multiplies, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator * (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::multiplies, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >
|
||||
operator * (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::multiplies, number<B, ET>, Arg1> (a, b.left_ref()));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >
|
||||
operator * (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiplies, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::multiplies, number<B, ET>, Arg1>(b, a.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator * (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator * (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B, et_on> >(b, a.left_ref()));
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > > >::type
|
||||
operator * (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > > (
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, V >(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator * (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > > (
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > > >::type
|
||||
operator * (const V& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, V > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, V >(b.left_ref(), a));
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator * (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> > >(
|
||||
detail::expression<detail::multiply_immediates, number<B, et_on>, number<B2, ET> >(b.left_ref(), a));
|
||||
}
|
||||
//
|
||||
// Division:
|
||||
//
|
||||
template <class B>
|
||||
inline detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >
|
||||
operator / (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::divide_immediates, number<B, et_on>, V > >::type
|
||||
operator / (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::divide_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::divide_immediates, V, number<B, et_on> > >::type
|
||||
operator / (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::divide_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::divides, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
operator / (const number<B, ET>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, number<B, ET>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
operator / (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
operator / (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator / (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::divides, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>, detail::expression<detail::divides, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator / (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::divides, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Repeat operator for negated arguments: propagate the negation to the top level to avoid temporaries:
|
||||
//
|
||||
template <class B, expression_template_option ET, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divides, number<B, ET>, Arg1> >
|
||||
operator / (const number<B, ET>& a, const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divides, number<B, ET>, Arg1> >(
|
||||
detail::expression<detail::divides, number<B, ET>, Arg1>(a, b.left_ref()));
|
||||
}
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divides, Arg1, number<B, ET> > >
|
||||
operator / (const detail::expression<detail::negate, Arg1, Arg2, Arg3, Arg4>& a, const number<B, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divides, Arg1, number<B, ET> > >(
|
||||
detail::expression<detail::divides, Arg1, number<B, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator / (const number<B, et_on>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
template <class B>
|
||||
inline detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >
|
||||
operator / (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, number<B, et_on> >(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, V > > >::type
|
||||
operator / (const detail::expression<detail::negate, number<B, et_on> >& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, V > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, V>(a.left_ref(), b));
|
||||
}
|
||||
template <class B, class B2, expression_template_option ET>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B2, ET> > > >::type
|
||||
operator / (const detail::expression<detail::negate, number<B, et_on> >& a, const number<B2, ET>& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B, et_on>, number<B2, ET> > >(
|
||||
detail::expression<detail::divide_immediates, number<B, et_on>, number<B2, ET> >(a.left_ref(), b));
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<V, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, V, number<B, et_on> > > >::type
|
||||
operator / (const V& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, V, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, V, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
template <class B2, expression_template_option ET, class B>
|
||||
inline typename enable_if<is_compatible_arithmetic_type<number<B2, ET>, number<B, et_on> >, detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B2, ET>, number<B, et_on> > > >::type
|
||||
operator / (const number<B2, ET>& a, const detail::expression<detail::negate, number<B, et_on> >& b)
|
||||
{
|
||||
return detail::expression<detail::negate, detail::expression<detail::divide_immediates, number<B2, ET>, number<B, et_on> > >(
|
||||
detail::expression<detail::divide_immediates, number<B2, ET>, number<B, et_on> >(a, b.left_ref()));
|
||||
}
|
||||
//
|
||||
// Modulus:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator % (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value && (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus_immediates, number<B, et_on>, V > >::type
|
||||
operator % (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::modulus_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value && (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus_immediates, V, number<B, et_on> > >::type
|
||||
operator % (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator % (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator % (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator % (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator % (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::modulus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator % (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::modulus, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Left shift:
|
||||
//
|
||||
template <class B, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), detail::expression<detail::shift_left, number<B, et_on>, I > >::type
|
||||
operator << (const number<B, et_on>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_left, number<B, et_on>, I>(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value && (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::shift_left, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I> >::type
|
||||
operator << (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_left, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I>(a, b);
|
||||
}
|
||||
//
|
||||
// Right shift:
|
||||
//
|
||||
template <class B, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::shift_right, number<B, et_on>, I > >::type
|
||||
operator >> (const number<B, et_on>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_right, number<B, et_on>, I>(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class I>
|
||||
inline typename enable_if_c<is_integral<I>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::shift_right, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I> >::type
|
||||
operator >> (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const I& b)
|
||||
{
|
||||
return detail::expression<detail::shift_right, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, I>(a, b);
|
||||
}
|
||||
//
|
||||
// Bitwise AND:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator & (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and_immediates, number<B, et_on>, V > >::type
|
||||
operator & (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and_immediates, V, number<B, et_on> > >::type
|
||||
operator & (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator & (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator & (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator & (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator & (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_and, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator & (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_and, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Bitwise OR:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator| (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or_immediates, number<B, et_on>, V > >::type
|
||||
operator| (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or_immediates, V, number<B, et_on> > >::type
|
||||
operator| (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator| (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator| (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator| (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator| (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_or, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator| (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_or, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
//
|
||||
// Bitwise XOR:
|
||||
//
|
||||
template <class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, number<B, et_on> > >::type
|
||||
operator^ (const number<B, et_on>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, V > >::type
|
||||
operator^ (const number<B, et_on>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor_immediates, number<B, et_on>, V >(a, b);
|
||||
}
|
||||
template <class V, class B>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_on> >::value
|
||||
&& (number_category<B>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_xor_immediates, V, number<B, et_on> > >::type
|
||||
operator^ (const V& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor_immediates, V, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class B, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator^ (const number<B, et_on>& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, number<B, et_on>, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B>
|
||||
inline typename enable_if_c<number_category<B>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> > >::type
|
||||
operator^ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const number<B, et_on>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, et_on> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tag2, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
inline typename enable_if_c<number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer,
|
||||
detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> > >::type
|
||||
operator^ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, detail::expression<tag2, Arg1b, Arg2b, Arg3b, Arg4b> >(a, b);
|
||||
}
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class V>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer),
|
||||
detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V > >::type
|
||||
operator^ (const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& a, const V& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, V >(a, b);
|
||||
}
|
||||
template <class V, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<V, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value
|
||||
&& (number_category<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == number_kind_integer), detail::expression<detail::bitwise_xor, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > >::type
|
||||
operator^ (const V& a, const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& b)
|
||||
{
|
||||
return detail::expression<detail::bitwise_xor, V, detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >(a, b);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Generic routines for converting floating point values to and from decimal strings.
|
||||
// Note that these use "naive" algorithms which result in rounding error - so they
|
||||
// do not round trip to and from the string representation (but should only be out
|
||||
// in the last bit).
|
||||
//
|
||||
|
||||
#ifndef BOOST_MP_FLOAT_STRING_CVT_HPP
|
||||
#define BOOST_MP_FLOAT_STRING_CVT_HPP
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
template <class I>
|
||||
inline void round_string_up_at(std::string& s, int pos, I& expon)
|
||||
{
|
||||
//
|
||||
// Rounds up a string representation of a number at pos:
|
||||
//
|
||||
if(pos < 0)
|
||||
{
|
||||
s.insert(static_cast<std::string::size_type>(0), 1, '1');
|
||||
s.erase(s.size() - 1);
|
||||
++expon;
|
||||
}
|
||||
else if(s[pos] == '9')
|
||||
{
|
||||
s[pos] = '0';
|
||||
round_string_up_at(s, pos - 1, expon);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((pos == 0) && (s[pos] == '0') && (s.size() == 1))
|
||||
++expon;
|
||||
++s[pos];
|
||||
}
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
std::string convert_to_string(Backend b, std::streamsize digits, std::ios_base::fmtflags f)
|
||||
{
|
||||
using default_ops::eval_log10;
|
||||
using default_ops::eval_floor;
|
||||
using default_ops::eval_pow;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_divide;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_fpclassify;
|
||||
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
typedef typename Backend::exponent_type exponent_type;
|
||||
|
||||
std::string result;
|
||||
bool iszero = false;
|
||||
bool isneg = false;
|
||||
exponent_type expon = 0;
|
||||
std::streamsize org_digits = digits;
|
||||
BOOST_ASSERT(digits > 0);
|
||||
|
||||
int fpt = eval_fpclassify(b);
|
||||
|
||||
if(fpt == (int)FP_ZERO)
|
||||
{
|
||||
result = "0";
|
||||
iszero = true;
|
||||
}
|
||||
else if(fpt == (int)FP_INFINITE)
|
||||
{
|
||||
if(b.compare(ui_type(0)) < 0)
|
||||
return "-inf";
|
||||
else
|
||||
return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf";
|
||||
}
|
||||
else if(fpt == (int)FP_NAN)
|
||||
{
|
||||
return "nan";
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Start by figuring out the exponent:
|
||||
//
|
||||
isneg = b.compare(ui_type(0)) < 0;
|
||||
if(isneg)
|
||||
b.negate();
|
||||
Backend t;
|
||||
Backend ten;
|
||||
ten = ui_type(10);
|
||||
|
||||
eval_log10(t, b);
|
||||
eval_floor(t, t);
|
||||
eval_convert_to(&expon, t);
|
||||
if(-expon > std::numeric_limits<number<Backend> >::max_exponent10 - 3)
|
||||
{
|
||||
int e = -expon / 2;
|
||||
Backend t2;
|
||||
eval_pow(t2, ten, e);
|
||||
eval_multiply(t, t2, b);
|
||||
eval_multiply(t, t2);
|
||||
if(expon & 1)
|
||||
eval_multiply(t, ten);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_pow(t, ten, -expon);
|
||||
eval_multiply(t, b);
|
||||
}
|
||||
//
|
||||
// Make sure we're between [1,10) and adjust if not:
|
||||
//
|
||||
if(t.compare(ui_type(1)) < 0)
|
||||
{
|
||||
eval_multiply(t, ui_type(10));
|
||||
--expon;
|
||||
}
|
||||
else if(t.compare(ui_type(10)) >= 0)
|
||||
{
|
||||
eval_divide(t, ui_type(10));
|
||||
++expon;
|
||||
}
|
||||
Backend digit;
|
||||
ui_type cdigit;
|
||||
//
|
||||
// Adjust the number of digits required based on formatting options:
|
||||
//
|
||||
if(((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1))
|
||||
digits += expon + 1;
|
||||
if((f & std::ios_base::scientific) == std::ios_base::scientific)
|
||||
++digits;
|
||||
//
|
||||
// Extract the digits one at a time:
|
||||
//
|
||||
for(unsigned i = 0; i < digits; ++i)
|
||||
{
|
||||
eval_floor(digit, t);
|
||||
eval_convert_to(&cdigit, digit);
|
||||
result += static_cast<char>('0' + cdigit);
|
||||
eval_subtract(t, digit);
|
||||
eval_multiply(t, ten);
|
||||
}
|
||||
//
|
||||
// Possibly round result:
|
||||
//
|
||||
if(digits >= 0)
|
||||
{
|
||||
eval_floor(digit, t);
|
||||
eval_convert_to(&cdigit, digit);
|
||||
eval_subtract(t, digit);
|
||||
if((cdigit == 5) && (t.compare(ui_type(0)) == 0))
|
||||
{
|
||||
// Bankers rounding:
|
||||
if((*result.rbegin() - '0') & 1)
|
||||
{
|
||||
round_string_up_at(result, result.size() - 1, expon);
|
||||
}
|
||||
}
|
||||
else if(cdigit >= 5)
|
||||
{
|
||||
round_string_up_at(result, result.size() - 1, expon);
|
||||
}
|
||||
}
|
||||
}
|
||||
while((result.size() > digits) && result.size())
|
||||
{
|
||||
// We may get here as a result of rounding...
|
||||
if(result.size() > 1)
|
||||
result.erase(result.size() - 1);
|
||||
else
|
||||
{
|
||||
if(expon > 0)
|
||||
--expon; // so we put less padding in the result.
|
||||
else
|
||||
++expon;
|
||||
++digits;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(org_digits >= 0);
|
||||
if(isneg)
|
||||
result.insert(static_cast<std::string::size_type>(0), 1, '-');
|
||||
format_float_string(result, expon, org_digits, f, iszero);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
void convert_from_string(Backend& b, const char* p)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_pow;
|
||||
using default_ops::eval_divide;
|
||||
|
||||
typedef typename mpl::front<typename Backend::unsigned_types>::type ui_type;
|
||||
b = ui_type(0);
|
||||
if(!p || (*p == 0))
|
||||
return;
|
||||
|
||||
bool is_neg = false;
|
||||
bool is_neg_expon = false;
|
||||
static const ui_type ten = ui_type(10);
|
||||
typename Backend::exponent_type expon = 0;
|
||||
int digits_seen = 0;
|
||||
typedef std::numeric_limits<number<Backend, et_off> > limits;
|
||||
static const int max_digits = limits::is_specialized ? limits::max_digits10 + 1 : INT_MAX;
|
||||
|
||||
if(*p == '+') ++p;
|
||||
else if(*p == '-')
|
||||
{
|
||||
is_neg = true;
|
||||
++p;
|
||||
}
|
||||
if((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0))
|
||||
{
|
||||
eval_divide(b, ui_type(0));
|
||||
if(is_neg)
|
||||
b.negate();
|
||||
return;
|
||||
}
|
||||
if((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0))
|
||||
{
|
||||
b = ui_type(1);
|
||||
eval_divide(b, ui_type(0));
|
||||
if(is_neg)
|
||||
b.negate();
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Grab all the leading digits before the decimal point:
|
||||
//
|
||||
while(std::isdigit(*p))
|
||||
{
|
||||
eval_multiply(b, ten);
|
||||
eval_add(b, ui_type(*p - '0'));
|
||||
++p;
|
||||
++digits_seen;
|
||||
}
|
||||
if(*p == '.')
|
||||
{
|
||||
//
|
||||
// Grab everything after the point, stop when we've seen
|
||||
// enough digits, even if there are actually more available:
|
||||
//
|
||||
++p;
|
||||
while(std::isdigit(*p))
|
||||
{
|
||||
eval_multiply(b, ten);
|
||||
eval_add(b, ui_type(*p - '0'));
|
||||
++p;
|
||||
--expon;
|
||||
if(++digits_seen > max_digits)
|
||||
break;
|
||||
}
|
||||
while(std::isdigit(*p))
|
||||
++p;
|
||||
}
|
||||
//
|
||||
// Parse the exponent:
|
||||
//
|
||||
if((*p == 'e') || (*p == 'E'))
|
||||
{
|
||||
++p;
|
||||
if(*p == '+') ++p;
|
||||
else if(*p == '-')
|
||||
{
|
||||
is_neg_expon = true;
|
||||
++p;
|
||||
}
|
||||
typename Backend::exponent_type e2 = 0;
|
||||
while(std::isdigit(*p))
|
||||
{
|
||||
e2 *= 10;
|
||||
e2 += (*p - '0');
|
||||
++p;
|
||||
}
|
||||
if(is_neg_expon)
|
||||
e2 = -e2;
|
||||
expon += e2;
|
||||
}
|
||||
if(expon)
|
||||
{
|
||||
// Scale by 10^expon, note that 10^expon can be
|
||||
// outside the range of our number type, even though the
|
||||
// result is within range, if that looks likely, then split
|
||||
// the calculation in two:
|
||||
Backend t;
|
||||
t = ten;
|
||||
if(expon > limits::min_exponent10 + 2)
|
||||
{
|
||||
eval_pow(t, t, expon);
|
||||
eval_multiply(b, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_pow(t, t, expon + digits_seen + 1);
|
||||
eval_multiply(b, t);
|
||||
t = ten;
|
||||
eval_pow(t, t, -digits_seen - 1);
|
||||
eval_multiply(b, t);
|
||||
}
|
||||
}
|
||||
if(is_neg)
|
||||
b.negate();
|
||||
if(*p)
|
||||
{
|
||||
// Unexpected input in string:
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected characters in string being interpreted as a float128."));
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,314 @@
|
||||
// Copyright 2011 John Maddock. Distributed under the Boost
|
||||
// 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)
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
|
||||
template <class T>
|
||||
void calc_log2(T& num, unsigned digits)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::signed_types>::type si_type;
|
||||
|
||||
//
|
||||
// String value with 1100 digits:
|
||||
//
|
||||
static const char* string_val = "0."
|
||||
"6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875"
|
||||
"4200148102057068573368552023575813055703267075163507596193072757082837143519030703862389167347112335"
|
||||
"0115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740"
|
||||
"4303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952"
|
||||
"6066834113727387372292895649354702576265209885969320196505855476470330679365443254763274495125040606"
|
||||
"9438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608"
|
||||
"2938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866"
|
||||
"3852313818167675143866747664789088143714198549423151997354880375165861275352916610007105355824987941"
|
||||
"4729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591"
|
||||
"0708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347"
|
||||
"6481149418642386776774406069562657379600867076257199184734022651462837904883062033061144630073719489";
|
||||
//
|
||||
// Check if we can just construct from string:
|
||||
//
|
||||
if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits
|
||||
{
|
||||
num = string_val;
|
||||
return;
|
||||
}
|
||||
//
|
||||
// We calculate log2 from using the formula:
|
||||
//
|
||||
// ln(2) = 3/4 SUM[n>=0] ((-1)^n * N!^2 / (2^n(2n+1)!))
|
||||
//
|
||||
// Numerator and denominator are calculated separately and then
|
||||
// divided at the end, we also precalculate the terms up to n = 5
|
||||
// since these fit in a 32-bit integer anyway.
|
||||
//
|
||||
// See Gourdon, X., and Sebah, P. The logarithmic constant: log 2, Jan. 2004.
|
||||
// Also http://www.mpfr.org/algorithms.pdf.
|
||||
//
|
||||
num = static_cast<ui_type>(1180509120uL);
|
||||
T denom, next_term, temp;
|
||||
denom = static_cast<ui_type>(1277337600uL);
|
||||
next_term = static_cast<ui_type>(120uL);
|
||||
si_type sign = -1;
|
||||
|
||||
ui_type limit = digits / 3 + 1;
|
||||
|
||||
for(ui_type n = 6; n < limit; ++n)
|
||||
{
|
||||
temp = static_cast<ui_type>(2);
|
||||
eval_multiply(temp, ui_type(2 * n));
|
||||
eval_multiply(temp, ui_type(2 * n + 1));
|
||||
eval_multiply(num, temp);
|
||||
eval_multiply(denom, temp);
|
||||
sign = -sign;
|
||||
eval_multiply(next_term, n);
|
||||
eval_multiply(temp, next_term, next_term);
|
||||
if(sign < 0)
|
||||
temp.negate();
|
||||
eval_add(num, temp);
|
||||
}
|
||||
eval_multiply(denom, ui_type(4));
|
||||
eval_multiply(num, ui_type(3));
|
||||
INSTRUMENT_BACKEND(denom);
|
||||
INSTRUMENT_BACKEND(num);
|
||||
eval_divide(num, denom);
|
||||
INSTRUMENT_BACKEND(num);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void calc_e(T& result, unsigned digits)
|
||||
{
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
//
|
||||
// 1100 digits in string form:
|
||||
//
|
||||
const char* string_val = "2."
|
||||
"7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274"
|
||||
"2746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901"
|
||||
"1573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069"
|
||||
"5517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416"
|
||||
"9283681902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312"
|
||||
"7736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117"
|
||||
"3012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509"
|
||||
"9618188159304169035159888851934580727386673858942287922849989208680582574927961048419844436346324496"
|
||||
"8487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016"
|
||||
"7683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354"
|
||||
"0212340784981933432106817012100562788023519303322474501585390473041995777709350366041699732972508869";
|
||||
//
|
||||
// Check if we can just construct from string:
|
||||
//
|
||||
if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits
|
||||
{
|
||||
result = string_val;
|
||||
return;
|
||||
}
|
||||
|
||||
T lim;
|
||||
lim = ui_type(1);
|
||||
eval_ldexp(lim, lim, digits);
|
||||
|
||||
//
|
||||
// Standard evaluation from the definition of e: http://functions.wolfram.com/Constants/E/02/
|
||||
//
|
||||
result = ui_type(2);
|
||||
T denom;
|
||||
denom = ui_type(1);
|
||||
ui_type i = 2;
|
||||
do{
|
||||
eval_multiply(denom, i);
|
||||
eval_multiply(result, i);
|
||||
eval_add(result, ui_type(1));
|
||||
++i;
|
||||
}while(denom.compare(lim) <= 0);
|
||||
eval_divide(result, denom);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void calc_pi(T& result, unsigned digits)
|
||||
{
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type real_type;
|
||||
//
|
||||
// 1100 digits in string form:
|
||||
//
|
||||
const char* string_val = "3."
|
||||
"1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
|
||||
"8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196"
|
||||
"4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273"
|
||||
"7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094"
|
||||
"3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912"
|
||||
"9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132"
|
||||
"0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235"
|
||||
"4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859"
|
||||
"5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303"
|
||||
"5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989"
|
||||
"3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913152";
|
||||
//
|
||||
// Check if we can just construct from string:
|
||||
//
|
||||
if(digits < 3640) // 3640 binary digits ~ 1100 decimal digits
|
||||
{
|
||||
result = string_val;
|
||||
return;
|
||||
}
|
||||
|
||||
T a;
|
||||
a = ui_type(1);
|
||||
T b;
|
||||
T A(a);
|
||||
T B;
|
||||
B = real_type(0.5f);
|
||||
T D;
|
||||
D = real_type(0.25f);
|
||||
|
||||
T lim;
|
||||
lim = ui_type(1);
|
||||
eval_ldexp(lim, lim, -(int)digits);
|
||||
|
||||
//
|
||||
// This algorithm is from:
|
||||
// Schonhage, A., Grotefeld, A. F. W., and Vetter, E. Fast Algorithms: A Multitape Turing
|
||||
// Machine Implementation. BI Wissenschaftverlag, 1994.
|
||||
// Also described in MPFR's algorithm guide: http://www.mpfr.org/algorithms.pdf.
|
||||
//
|
||||
// Let:
|
||||
// a[0] = A[0] = 1
|
||||
// B[0] = 1/2
|
||||
// D[0] = 1/4
|
||||
// Then:
|
||||
// S[k+1] = (A[k]+B[k]) / 4
|
||||
// b[k] = sqrt(B[k])
|
||||
// a[k+1] = a[k]^2
|
||||
// B[k+1] = 2(A[k+1]-S[k+1])
|
||||
// D[k+1] = D[k] - 2^k(A[k+1]-B[k+1])
|
||||
// Stop when |A[k]-B[k]| <= 2^(k-p)
|
||||
// and PI = B[k]/D[k]
|
||||
|
||||
unsigned k = 1;
|
||||
|
||||
do
|
||||
{
|
||||
eval_add(result, A, B);
|
||||
eval_ldexp(result, result, -2);
|
||||
eval_sqrt(b, B);
|
||||
eval_add(a, b);
|
||||
eval_ldexp(a, a, -1);
|
||||
eval_multiply(A, a, a);
|
||||
eval_subtract(B, A, result);
|
||||
eval_ldexp(B, B, 1);
|
||||
eval_subtract(result, A, B);
|
||||
bool neg = eval_get_sign(result) < 0;
|
||||
if(neg)
|
||||
result.negate();
|
||||
if(result.compare(lim) <= 0)
|
||||
break;
|
||||
if(neg)
|
||||
result.negate();
|
||||
eval_ldexp(result, result, k - 1);
|
||||
eval_subtract(D, result);
|
||||
++k;
|
||||
eval_ldexp(lim, lim, 1);
|
||||
}
|
||||
while(true);
|
||||
|
||||
eval_divide(result, B, D);
|
||||
}
|
||||
|
||||
template <class T, const T& (*F)(void)>
|
||||
struct constant_initializer
|
||||
{
|
||||
static void do_nothing()
|
||||
{
|
||||
init.do_nothing();
|
||||
}
|
||||
private:
|
||||
struct initializer
|
||||
{
|
||||
initializer()
|
||||
{
|
||||
F();
|
||||
}
|
||||
void do_nothing()const{}
|
||||
};
|
||||
static const initializer init;
|
||||
};
|
||||
|
||||
template <class T, const T& (*F)(void)>
|
||||
typename constant_initializer<T, F>::initializer const constant_initializer<T, F>::init;
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_ln2()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
calc_log2(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_ln2<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
#ifndef BOOST_MP_THREAD_LOCAL
|
||||
#error 1
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_e()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
calc_e(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_e<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_pi()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
calc_pi(result, boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_pi<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_one_over_epsilon()
|
||||
{
|
||||
static const bool is_init = false;
|
||||
static T result;
|
||||
if (is_init == false)
|
||||
{
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
result = static_cast<ui_type>(1u);
|
||||
eval_divide(result, std::numeric_limits<number<T> >::epsilon().backend());
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_one_over_epsilon<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,904 @@
|
||||
|
||||
// Copyright Christopher Kormanyos 2002 - 2013.
|
||||
// Copyright 2011 - 2013 John Maddock. Distributed under the Boost
|
||||
// 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)
|
||||
|
||||
// This work is based on an earlier work:
|
||||
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
|
||||
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:6326) // comparison of two constants
|
||||
#endif
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T, typename U>
|
||||
inline void pow_imp(T& result, const T& t, const U& p, const mpl::false_&)
|
||||
{
|
||||
// Compute the pure power of typename T t^p.
|
||||
// Use the S-and-X binary method, as described in
|
||||
// D. E. Knuth, "The Art of Computer Programming", Vol. 2,
|
||||
// Section 4.6.3 . The resulting computational complexity
|
||||
// is order log2[abs(p)].
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<U, T>::type int_type;
|
||||
|
||||
if(&result == &t)
|
||||
{
|
||||
T temp;
|
||||
pow_imp(temp, t, p, mpl::false_());
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
|
||||
// This will store the result.
|
||||
if(U(p % U(2)) != U(0))
|
||||
{
|
||||
result = t;
|
||||
}
|
||||
else
|
||||
result = int_type(1);
|
||||
|
||||
U p2(p);
|
||||
|
||||
// The variable x stores the binary powers of t.
|
||||
T x(t);
|
||||
|
||||
while(U(p2 /= 2) != U(0))
|
||||
{
|
||||
// Square x for each binary power.
|
||||
eval_multiply(x, x);
|
||||
|
||||
const bool has_binary_power = (U(p2 % U(2)) != U(0));
|
||||
|
||||
if(has_binary_power)
|
||||
{
|
||||
// Multiply the result with each binary power contained in the exponent.
|
||||
eval_multiply(result, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline void pow_imp(T& result, const T& t, const U& p, const mpl::true_&)
|
||||
{
|
||||
// Signed integer power, just take care of the sign then call the unsigned version:
|
||||
typedef typename boost::multiprecision::detail::canonical<U, T>::type int_type;
|
||||
typedef typename make_unsigned<U>::type ui_type;
|
||||
|
||||
if(p < 0)
|
||||
{
|
||||
T temp;
|
||||
temp = static_cast<int_type>(1);
|
||||
T denom;
|
||||
pow_imp(denom, t, static_cast<ui_type>(-p), mpl::false_());
|
||||
eval_divide(result, temp, denom);
|
||||
return;
|
||||
}
|
||||
pow_imp(result, t, static_cast<ui_type>(p), mpl::false_());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename U>
|
||||
inline typename enable_if_c<is_integral<U>::value>::type eval_pow(T& result, const T& t, const U& p)
|
||||
{
|
||||
detail::pow_imp(result, t, p, boost::is_signed<U>());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hyp0F0(T& H0F0, const T& x)
|
||||
{
|
||||
// Compute the series representation of Hypergeometric0F0 taken from
|
||||
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F0/06/01/
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
|
||||
|
||||
BOOST_ASSERT(&H0F0 != &x);
|
||||
long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
T t;
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
|
||||
eval_add(H0F0, x_pow_n_div_n_fact, ui_type(1));
|
||||
|
||||
T lim;
|
||||
eval_ldexp(lim, H0F0, 1 - tol);
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
|
||||
ui_type n;
|
||||
|
||||
const unsigned series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_0f0(; ; x).
|
||||
for(n = 2; n < series_limit; ++n)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
eval_add(H0F0, x_pow_n_div_n_fact);
|
||||
bool neg = eval_get_sign(x_pow_n_div_n_fact) < 0;
|
||||
if(neg)
|
||||
x_pow_n_div_n_fact.negate();
|
||||
if(lim.compare(x_pow_n_div_n_fact) > 0)
|
||||
break;
|
||||
if(neg)
|
||||
x_pow_n_div_n_fact.negate();
|
||||
}
|
||||
if(n >= series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge"));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hyp1F0(T& H1F0, const T& a, const T& x)
|
||||
{
|
||||
// Compute the series representation of Hypergeometric1F0 taken from
|
||||
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric1F0/06/01/01/
|
||||
// and also see the corresponding section for the power function (i.e. x^a).
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type;
|
||||
|
||||
BOOST_ASSERT(&H1F0 != &x);
|
||||
BOOST_ASSERT(&H1F0 != &a);
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
T pochham_a (a);
|
||||
T ap (a);
|
||||
|
||||
eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact);
|
||||
eval_add(H1F0, si_type(1));
|
||||
T lim;
|
||||
eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
|
||||
si_type n;
|
||||
T term, part;
|
||||
|
||||
const si_type series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_1f0(a; ; x).
|
||||
for(n = 2; n < series_limit; n++)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
eval_increment(ap);
|
||||
eval_multiply(pochham_a, ap);
|
||||
eval_multiply(term, pochham_a, x_pow_n_div_n_fact);
|
||||
eval_add(H1F0, term);
|
||||
if(eval_get_sign(term) < 0)
|
||||
term.negate();
|
||||
if(lim.compare(term) >= 0)
|
||||
break;
|
||||
}
|
||||
if(n >= series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge"));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_exp(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The exp function is only valid for floating point types.");
|
||||
if(&x == &result)
|
||||
{
|
||||
T temp;
|
||||
eval_exp(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type;
|
||||
typedef typename T::exponent_type exp_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type;
|
||||
|
||||
// Handle special arguments.
|
||||
int type = eval_fpclassify(x);
|
||||
bool isneg = eval_get_sign(x) < 0;
|
||||
if(type == (int)FP_NAN)
|
||||
{
|
||||
result = x;
|
||||
errno = EDOM;
|
||||
return;
|
||||
}
|
||||
else if(type == (int)FP_INFINITE)
|
||||
{
|
||||
if(isneg)
|
||||
result = ui_type(0u);
|
||||
else
|
||||
result = x;
|
||||
return;
|
||||
}
|
||||
else if(type == (int)FP_ZERO)
|
||||
{
|
||||
result = ui_type(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get local copy of argument and force it to be positive.
|
||||
T xx = x;
|
||||
T exp_series;
|
||||
if(isneg)
|
||||
xx.negate();
|
||||
|
||||
// Check the range of the argument.
|
||||
if(xx.compare(si_type(1)) <= 0)
|
||||
{
|
||||
//
|
||||
// Use series for exp(x) - 1:
|
||||
//
|
||||
T lim;
|
||||
if(std::numeric_limits<number<T, et_on> >::is_specialized)
|
||||
lim = std::numeric_limits<number<T, et_on> >::epsilon().backend();
|
||||
else
|
||||
{
|
||||
result = ui_type(1);
|
||||
eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
}
|
||||
unsigned k = 2;
|
||||
exp_series = xx;
|
||||
result = si_type(1);
|
||||
if(isneg)
|
||||
eval_subtract(result, exp_series);
|
||||
else
|
||||
eval_add(result, exp_series);
|
||||
eval_multiply(exp_series, xx);
|
||||
eval_divide(exp_series, ui_type(k));
|
||||
eval_add(result, exp_series);
|
||||
while(exp_series.compare(lim) > 0)
|
||||
{
|
||||
++k;
|
||||
eval_multiply(exp_series, xx);
|
||||
eval_divide(exp_series, ui_type(k));
|
||||
if(isneg && (k&1))
|
||||
eval_subtract(result, exp_series);
|
||||
else
|
||||
eval_add(result, exp_series);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for pure-integer arguments which can be either signed or unsigned.
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type ll;
|
||||
eval_trunc(exp_series, x);
|
||||
eval_convert_to(&ll, exp_series);
|
||||
if(x.compare(ll) == 0)
|
||||
{
|
||||
detail::pow_imp(result, get_constant_e<T>(), ll, mpl::true_());
|
||||
return;
|
||||
}
|
||||
else if(exp_series.compare(x) == 0)
|
||||
{
|
||||
// We have a value that has no fractional part, but is too large to fit
|
||||
// in a long long, in this situation the code below will fail, so
|
||||
// we're just going to assume that this will overflow:
|
||||
if(isneg)
|
||||
result = ui_type(0);
|
||||
else
|
||||
result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
|
||||
return;
|
||||
}
|
||||
|
||||
// The algorithm for exp has been taken from MPFUN.
|
||||
// exp(t) = [ (1 + r + r^2/2! + r^3/3! + r^4/4! ...)^p2 ] * 2^n
|
||||
// where p2 is a power of 2 such as 2048, r = t_prime / p2, and
|
||||
// t_prime = t - n*ln2, with n chosen to minimize the absolute
|
||||
// value of t_prime. In the resulting Taylor series, which is
|
||||
// implemented as a hypergeometric function, |r| is bounded by
|
||||
// ln2 / p2. For small arguments, no scaling is done.
|
||||
|
||||
// Compute the exponential series of the (possibly) scaled argument.
|
||||
|
||||
eval_divide(result, xx, get_constant_ln2<T>());
|
||||
exp_type n;
|
||||
eval_convert_to(&n, result);
|
||||
|
||||
if (n == (std::numeric_limits<exp_type>::max)())
|
||||
{
|
||||
// Exponent is too large to fit in our exponent type:
|
||||
if (isneg)
|
||||
result = ui_type(0);
|
||||
else
|
||||
result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
|
||||
return;
|
||||
}
|
||||
|
||||
// The scaling is 2^11 = 2048.
|
||||
const si_type p2 = static_cast<si_type>(si_type(1) << 11);
|
||||
|
||||
eval_multiply(exp_series, get_constant_ln2<T>(), static_cast<canonical_exp_type>(n));
|
||||
eval_subtract(exp_series, xx);
|
||||
eval_divide(exp_series, p2);
|
||||
exp_series.negate();
|
||||
hyp0F0(result, exp_series);
|
||||
|
||||
detail::pow_imp(exp_series, result, p2, mpl::true_());
|
||||
result = ui_type(1);
|
||||
eval_ldexp(result, result, n);
|
||||
eval_multiply(exp_series, result);
|
||||
|
||||
if(isneg)
|
||||
eval_divide(result, ui_type(1), exp_series);
|
||||
else
|
||||
result = exp_series;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_log(T& result, const T& arg)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
|
||||
//
|
||||
// We use a variation of http://dlmf.nist.gov/4.45#i
|
||||
// using frexp to reduce the argument to x * 2^n,
|
||||
// then let y = x - 1 and compute:
|
||||
// log(x) = log(2) * n + log1p(1 + y)
|
||||
//
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
typedef typename T::exponent_type exp_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<exp_type, T>::type canonical_exp_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
int s = eval_signbit(arg);
|
||||
switch(eval_fpclassify(arg))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = arg;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_INFINITE:
|
||||
if(s) break;
|
||||
result = arg;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
|
||||
result.negate();
|
||||
errno = ERANGE;
|
||||
return;
|
||||
}
|
||||
if(s)
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
return;
|
||||
}
|
||||
|
||||
exp_type e;
|
||||
T t;
|
||||
eval_frexp(t, arg, &e);
|
||||
bool alternate = false;
|
||||
|
||||
if(t.compare(fp_type(2) / fp_type(3)) <= 0)
|
||||
{
|
||||
alternate = true;
|
||||
eval_ldexp(t, t, 1);
|
||||
--e;
|
||||
}
|
||||
|
||||
eval_multiply(result, get_constant_ln2<T>(), canonical_exp_type(e));
|
||||
INSTRUMENT_BACKEND(result);
|
||||
eval_subtract(t, ui_type(1)); /* -0.3 <= t <= 0.3 */
|
||||
if(!alternate)
|
||||
t.negate(); /* 0 <= t <= 0.33333 */
|
||||
T pow = t;
|
||||
T lim;
|
||||
T t2;
|
||||
|
||||
if(alternate)
|
||||
eval_add(result, t);
|
||||
else
|
||||
eval_subtract(result, t);
|
||||
|
||||
if(std::numeric_limits<number<T, et_on> >::is_specialized)
|
||||
eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend());
|
||||
else
|
||||
eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
INSTRUMENT_BACKEND(lim);
|
||||
|
||||
ui_type k = 1;
|
||||
do
|
||||
{
|
||||
++k;
|
||||
eval_multiply(pow, t);
|
||||
eval_divide(t2, pow, k);
|
||||
INSTRUMENT_BACKEND(t2);
|
||||
if(alternate && ((k & 1) != 0))
|
||||
eval_add(result, t2);
|
||||
else
|
||||
eval_subtract(result, t2);
|
||||
INSTRUMENT_BACKEND(result);
|
||||
}while(lim.compare(t2) < 0);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T& get_constant_log10()
|
||||
{
|
||||
static BOOST_MP_THREAD_LOCAL T result;
|
||||
static BOOST_MP_THREAD_LOCAL bool b = false;
|
||||
static BOOST_MP_THREAD_LOCAL long digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
if(!b || (digits != boost::multiprecision::detail::digits2<number<T> >::value()))
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
T ten;
|
||||
ten = ui_type(10u);
|
||||
eval_log(result, ten);
|
||||
b = true;
|
||||
digits = boost::multiprecision::detail::digits2<number<T> >::value();
|
||||
}
|
||||
|
||||
constant_initializer<T, &get_constant_log10<T> >::do_nothing();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_log10(T& result, const T& arg)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log10 function is only valid for floating point types.");
|
||||
eval_log(result, arg);
|
||||
eval_divide(result, get_constant_log10<T>());
|
||||
}
|
||||
|
||||
template <class R, class T>
|
||||
inline void eval_log2(R& result, const T& a)
|
||||
{
|
||||
eval_log(result, a);
|
||||
eval_divide(result, get_constant_ln2<R>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void eval_pow(T& result, const T& x, const T& a)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The pow function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<int, T>::type si_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
if((&result == &x) || (&result == &a))
|
||||
{
|
||||
T t;
|
||||
eval_pow(t, x, a);
|
||||
result = t;
|
||||
return;
|
||||
}
|
||||
|
||||
if((a.compare(si_type(1)) == 0) || (x.compare(si_type(1)) == 0))
|
||||
{
|
||||
result = x;
|
||||
return;
|
||||
}
|
||||
if(a.compare(si_type(0)) == 0)
|
||||
{
|
||||
result = si_type(1);
|
||||
return;
|
||||
}
|
||||
|
||||
int type = eval_fpclassify(x);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case FP_ZERO:
|
||||
switch(eval_fpclassify(a))
|
||||
{
|
||||
case FP_ZERO:
|
||||
result = si_type(1);
|
||||
break;
|
||||
case FP_NAN:
|
||||
result = a;
|
||||
break;
|
||||
case FP_NORMAL:
|
||||
{
|
||||
// Need to check for a an odd integer as a special case:
|
||||
try
|
||||
{
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type i;
|
||||
eval_convert_to(&i, a);
|
||||
if(a.compare(i) == 0)
|
||||
{
|
||||
if(eval_signbit(a))
|
||||
{
|
||||
if(i & 1)
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::infinity().backend();
|
||||
if(eval_signbit(x))
|
||||
result.negate();
|
||||
errno = ERANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::infinity().backend();
|
||||
errno = ERANGE;
|
||||
}
|
||||
}
|
||||
else if(i & 1)
|
||||
{
|
||||
result = x;
|
||||
}
|
||||
else
|
||||
result = si_type(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// fallthrough..
|
||||
}
|
||||
}
|
||||
default:
|
||||
if(eval_signbit(a))
|
||||
{
|
||||
result = std::numeric_limits<number<T> >::infinity().backend();
|
||||
errno = ERANGE;
|
||||
}
|
||||
else
|
||||
result = x;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case FP_NAN:
|
||||
result = x;
|
||||
errno = ERANGE;
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
int s = eval_get_sign(a);
|
||||
if(s == 0)
|
||||
{
|
||||
result = si_type(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if(s < 0)
|
||||
{
|
||||
T t, da;
|
||||
t = a;
|
||||
t.negate();
|
||||
eval_pow(da, x, t);
|
||||
eval_divide(result, si_type(1), da);
|
||||
return;
|
||||
}
|
||||
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type an;
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type max_an =
|
||||
std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::is_specialized ?
|
||||
(std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::max)() :
|
||||
static_cast<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>(1) << (sizeof(typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type) * CHAR_BIT - 2);
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type min_an =
|
||||
std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::is_specialized ?
|
||||
(std::numeric_limits<typename boost::multiprecision::detail::canonical<boost::intmax_t, T>::type>::min)() :
|
||||
-min_an;
|
||||
|
||||
|
||||
T fa;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
eval_convert_to(&an, a);
|
||||
if(a.compare(an) == 0)
|
||||
{
|
||||
detail::pow_imp(result, x, an, mpl::true_());
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// conversion failed, just fall through, value is not an integer.
|
||||
an = (std::numeric_limits<boost::intmax_t>::max)();
|
||||
}
|
||||
#endif
|
||||
if((eval_get_sign(x) < 0))
|
||||
{
|
||||
typename boost::multiprecision::detail::canonical<boost::uintmax_t, T>::type aun;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
eval_convert_to(&aun, a);
|
||||
if(a.compare(aun) == 0)
|
||||
{
|
||||
fa = x;
|
||||
fa.negate();
|
||||
eval_pow(result, fa, a);
|
||||
if(aun & 1u)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// conversion failed, just fall through, value is not an integer.
|
||||
}
|
||||
#endif
|
||||
eval_floor(result, a);
|
||||
// -1^INF is a special case in C99:
|
||||
if((x.compare(si_type(-1)) == 0) && (eval_fpclassify(a) == FP_INFINITE))
|
||||
{
|
||||
result = si_type(1);
|
||||
}
|
||||
else if(a.compare(result) == 0)
|
||||
{
|
||||
// exponent is so large we have no fractional part:
|
||||
if(x.compare(si_type(-1)) < 0)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::infinity().backend();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = si_type(0);
|
||||
}
|
||||
}
|
||||
else if(type == FP_INFINITE)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::infinity().backend();
|
||||
}
|
||||
else if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
T t, da;
|
||||
|
||||
eval_subtract(da, a, an);
|
||||
|
||||
if((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0) && (an < max_an) && (an > min_an))
|
||||
{
|
||||
if(a.compare(fp_type(1e-5f)) <= 0)
|
||||
{
|
||||
// Series expansion for small a.
|
||||
eval_log(t, x);
|
||||
eval_multiply(t, a);
|
||||
hyp0F0(result, t);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Series expansion for moderately sized x. Note that for large power of a,
|
||||
// the power of the integer part of a is calculated using the pown function.
|
||||
if(an)
|
||||
{
|
||||
da.negate();
|
||||
t = si_type(1);
|
||||
eval_subtract(t, x);
|
||||
hyp1F0(result, da, t);
|
||||
detail::pow_imp(t, x, an, mpl::true_());
|
||||
eval_multiply(result, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
da = a;
|
||||
da.negate();
|
||||
t = si_type(1);
|
||||
eval_subtract(t, x);
|
||||
hyp1F0(result, da, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Series expansion for pow(x, a). Note that for large power of a, the power
|
||||
// of the integer part of a is calculated using the pown function.
|
||||
if(an)
|
||||
{
|
||||
eval_log(t, x);
|
||||
eval_multiply(t, da);
|
||||
eval_exp(result, t);
|
||||
detail::pow_imp(t, x, an, mpl::true_());
|
||||
eval_multiply(result, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_log(t, x);
|
||||
eval_multiply(t, a);
|
||||
eval_exp(result, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
|
||||
inline typename enable_if_c<!is_integral<A>::value, void>::type
|
||||
#else
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<A, number<T> >::value && !is_integral<A>::value, void>::type
|
||||
#endif
|
||||
eval_pow(T& result, const T& x, const A& a)
|
||||
{
|
||||
// Note this one is restricted to float arguments since pow.hpp already has a version for
|
||||
// integer powers....
|
||||
typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
|
||||
typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
|
||||
cast_type c;
|
||||
c = a;
|
||||
eval_pow(result, x, c);
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
|
||||
inline void
|
||||
#else
|
||||
inline typename enable_if_c<is_compatible_arithmetic_type<A, number<T> >::value, void>::type
|
||||
#endif
|
||||
eval_pow(T& result, const A& x, const T& a)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
|
||||
typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
|
||||
cast_type c;
|
||||
c = x;
|
||||
eval_pow(result, c, a);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_exp2(T& result, const T& arg)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
|
||||
|
||||
// Check for pure-integer arguments which can be either signed or unsigned.
|
||||
typename boost::multiprecision::detail::canonical<typename T::exponent_type, T>::type i;
|
||||
T temp;
|
||||
try {
|
||||
eval_trunc(temp, arg);
|
||||
eval_convert_to(&i, temp);
|
||||
if(arg.compare(i) == 0)
|
||||
{
|
||||
temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
|
||||
eval_ldexp(result, temp, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(const boost::math::rounding_error&)
|
||||
{ /* Fallthrough */ }
|
||||
catch(const std::runtime_error&)
|
||||
{ /* Fallthrough */ }
|
||||
|
||||
temp = static_cast<typename mpl::front<typename T::unsigned_types>::type>(2u);
|
||||
eval_pow(result, temp, arg);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class T>
|
||||
void small_sinh_series(T x, T& result)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
bool neg = eval_get_sign(x) < 0;
|
||||
if(neg)
|
||||
x.negate();
|
||||
T p(x);
|
||||
T mult(x);
|
||||
eval_multiply(mult, x);
|
||||
result = x;
|
||||
ui_type k = 1;
|
||||
|
||||
T lim(x);
|
||||
eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
|
||||
do
|
||||
{
|
||||
eval_multiply(p, mult);
|
||||
eval_divide(p, ++k);
|
||||
eval_divide(p, ++k);
|
||||
eval_add(result, p);
|
||||
}while(p.compare(lim) >= 0);
|
||||
if(neg)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sinhcosh(const T& x, T* p_sinh, T* p_cosh)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
errno = EDOM;
|
||||
// fallthrough...
|
||||
case FP_INFINITE:
|
||||
if(p_sinh)
|
||||
*p_sinh = x;
|
||||
if(p_cosh)
|
||||
{
|
||||
*p_cosh = x;
|
||||
if(eval_get_sign(x) < 0)
|
||||
p_cosh->negate();
|
||||
}
|
||||
return;
|
||||
case FP_ZERO:
|
||||
if(p_sinh)
|
||||
*p_sinh = x;
|
||||
if(p_cosh)
|
||||
*p_cosh = ui_type(1);
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
bool small_sinh = eval_get_sign(x) < 0 ? x.compare(fp_type(-0.5)) > 0 : x.compare(fp_type(0.5)) < 0;
|
||||
|
||||
if(p_cosh || !small_sinh)
|
||||
{
|
||||
T e_px, e_mx;
|
||||
eval_exp(e_px, x);
|
||||
eval_divide(e_mx, ui_type(1), e_px);
|
||||
if(eval_signbit(e_mx) != eval_signbit(e_px))
|
||||
e_mx.negate(); // Handles lack of signed zero in some types
|
||||
|
||||
if(p_sinh)
|
||||
{
|
||||
if(small_sinh)
|
||||
{
|
||||
small_sinh_series(x, *p_sinh);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_subtract(*p_sinh, e_px, e_mx);
|
||||
eval_ldexp(*p_sinh, *p_sinh, -1);
|
||||
}
|
||||
}
|
||||
if(p_cosh)
|
||||
{
|
||||
eval_add(*p_cosh, e_px, e_mx);
|
||||
eval_ldexp(*p_cosh, *p_cosh, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
small_sinh_series(x, *p_sinh);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline void eval_sinh(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The sinh function is only valid for floating point types.");
|
||||
detail::sinhcosh(x, &result, static_cast<T*>(0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void eval_cosh(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The cosh function is only valid for floating point types.");
|
||||
detail::sinhcosh(x, static_cast<T*>(0), &result);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void eval_tanh(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The tanh function is only valid for floating point types.");
|
||||
T c;
|
||||
detail::sinhcosh(x, &result, &c);
|
||||
if((eval_fpclassify(result) == FP_INFINITE) && (eval_fpclassify(c) == FP_INFINITE))
|
||||
{
|
||||
bool s = eval_signbit(result) != eval_signbit(c);
|
||||
result = static_cast<typename mpl::front<typename T::unsigned_types>::type>(1u);
|
||||
if(s)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
eval_divide(result, c);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -0,0 +1,844 @@
|
||||
|
||||
// Copyright Christopher Kormanyos 2002 - 2011.
|
||||
// Copyright 2011 John Maddock. Distributed under the Boost
|
||||
// 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)
|
||||
|
||||
// This work is based on an earlier work:
|
||||
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
|
||||
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
|
||||
//
|
||||
// This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
|
||||
//
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:6326) // comparison of two constants
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
void hyp0F1(T& result, const T& b, const T& x)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
// Compute the series representation of Hypergeometric0F1 taken from
|
||||
// http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F1/06/01/01/
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
T pochham_b (b);
|
||||
T bp (b);
|
||||
|
||||
eval_divide(result, x_pow_n_div_n_fact, pochham_b);
|
||||
eval_add(result, ui_type(1));
|
||||
|
||||
si_type n;
|
||||
|
||||
T tol;
|
||||
tol = ui_type(1);
|
||||
eval_ldexp(tol, tol, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
eval_multiply(tol, result);
|
||||
if(eval_get_sign(tol) < 0)
|
||||
tol.negate();
|
||||
T term;
|
||||
|
||||
const int series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_0f1(; b; x).
|
||||
for(n = 2; n < series_limit; ++n)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
eval_increment(bp);
|
||||
eval_multiply(pochham_b, bp);
|
||||
|
||||
eval_divide(term, x_pow_n_div_n_fact, pochham_b);
|
||||
eval_add(result, term);
|
||||
|
||||
bool neg_term = eval_get_sign(term) < 0;
|
||||
if(neg_term)
|
||||
term.negate();
|
||||
if(term.compare(tol) <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(n >= series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H0F1 Failed to Converge"));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void eval_sin(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The sin function is only valid for floating point types.");
|
||||
if(&result == &x)
|
||||
{
|
||||
T temp;
|
||||
eval_sin(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = x;
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
// Local copy of the argument
|
||||
T xx = x;
|
||||
|
||||
// Analyze and prepare the phase of the argument.
|
||||
// Make a local, positive copy of the argument, xx.
|
||||
// The argument xx will be reduced to 0 <= xx <= pi/2.
|
||||
bool b_negate_sin = false;
|
||||
|
||||
if(eval_get_sign(x) < 0)
|
||||
{
|
||||
xx.negate();
|
||||
b_negate_sin = !b_negate_sin;
|
||||
}
|
||||
|
||||
T n_pi, t;
|
||||
// Remove even multiples of pi.
|
||||
if(xx.compare(get_constant_pi<T>()) > 0)
|
||||
{
|
||||
eval_divide(n_pi, xx, get_constant_pi<T>());
|
||||
eval_trunc(n_pi, n_pi);
|
||||
t = ui_type(2);
|
||||
eval_fmod(t, n_pi, t);
|
||||
const bool b_n_pi_is_even = eval_get_sign(t) == 0;
|
||||
eval_multiply(n_pi, get_constant_pi<T>());
|
||||
if (n_pi.compare(get_constant_one_over_epsilon<T>()) > 0)
|
||||
{
|
||||
result = ui_type(0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
eval_subtract(xx, n_pi);
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific));
|
||||
|
||||
// Adjust signs if the multiple of pi is not even.
|
||||
if(!b_n_pi_is_even)
|
||||
{
|
||||
b_negate_sin = !b_negate_sin;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce the argument to 0 <= xx <= pi/2.
|
||||
eval_ldexp(t, get_constant_pi<T>(), -1);
|
||||
if(xx.compare(t) > 0)
|
||||
{
|
||||
eval_subtract(xx, get_constant_pi<T>(), xx);
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
}
|
||||
|
||||
eval_subtract(t, xx);
|
||||
const bool b_zero = eval_get_sign(xx) == 0;
|
||||
const bool b_pi_half = eval_get_sign(t) == 0;
|
||||
|
||||
// Check if the reduced argument is very close to 0 or pi/2.
|
||||
const bool b_near_zero = xx.compare(fp_type(1e-1)) < 0;
|
||||
const bool b_near_pi_half = t.compare(fp_type(1e-1)) < 0;;
|
||||
|
||||
if(b_zero)
|
||||
{
|
||||
result = ui_type(0);
|
||||
}
|
||||
else if(b_pi_half)
|
||||
{
|
||||
result = ui_type(1);
|
||||
}
|
||||
else if(b_near_zero)
|
||||
{
|
||||
eval_multiply(t, xx, xx);
|
||||
eval_divide(t, si_type(-4));
|
||||
T t2;
|
||||
t2 = fp_type(1.5);
|
||||
hyp0F1(result, t2, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
eval_multiply(result, xx);
|
||||
}
|
||||
else if(b_near_pi_half)
|
||||
{
|
||||
eval_multiply(t, t);
|
||||
eval_divide(t, si_type(-4));
|
||||
T t2;
|
||||
t2 = fp_type(0.5);
|
||||
hyp0F1(result, t2, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scale to a small argument for an efficient Taylor series,
|
||||
// implemented as a hypergeometric function. Use a standard
|
||||
// divide by three identity a certain number of times.
|
||||
// Here we use division by 3^9 --> (19683 = 3^9).
|
||||
|
||||
static const si_type n_scale = 9;
|
||||
static const si_type n_three_pow_scale = static_cast<si_type>(19683L);
|
||||
|
||||
eval_divide(xx, n_three_pow_scale);
|
||||
|
||||
// Now with small arguments, we are ready for a series expansion.
|
||||
eval_multiply(t, xx, xx);
|
||||
eval_divide(t, si_type(-4));
|
||||
T t2;
|
||||
t2 = fp_type(1.5);
|
||||
hyp0F1(result, t2, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
eval_multiply(result, xx);
|
||||
|
||||
// Convert back using multiple angle identity.
|
||||
for(boost::int32_t k = static_cast<boost::int32_t>(0); k < n_scale; k++)
|
||||
{
|
||||
// Rescale the cosine value using the multiple angle identity.
|
||||
eval_multiply(t2, result, ui_type(3));
|
||||
eval_multiply(t, result, result);
|
||||
eval_multiply(t, result);
|
||||
eval_multiply(t, ui_type(4));
|
||||
eval_subtract(result, t2, t);
|
||||
}
|
||||
}
|
||||
|
||||
if(b_negate_sin)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_cos(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The cos function is only valid for floating point types.");
|
||||
if(&result == &x)
|
||||
{
|
||||
T temp;
|
||||
eval_cos(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = ui_type(1);
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
// Local copy of the argument
|
||||
T xx = x;
|
||||
|
||||
// Analyze and prepare the phase of the argument.
|
||||
// Make a local, positive copy of the argument, xx.
|
||||
// The argument xx will be reduced to 0 <= xx <= pi/2.
|
||||
bool b_negate_cos = false;
|
||||
|
||||
if(eval_get_sign(x) < 0)
|
||||
{
|
||||
xx.negate();
|
||||
}
|
||||
|
||||
T n_pi, t;
|
||||
// Remove even multiples of pi.
|
||||
if(xx.compare(get_constant_pi<T>()) > 0)
|
||||
{
|
||||
eval_divide(t, xx, get_constant_pi<T>());
|
||||
eval_trunc(n_pi, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(n_pi.str(0, std::ios_base::scientific));
|
||||
eval_multiply(t, n_pi, get_constant_pi<T>());
|
||||
BOOST_MATH_INSTRUMENT_CODE(t.str(0, std::ios_base::scientific));
|
||||
//
|
||||
// If t is so large that all digits cancel the result of this subtraction
|
||||
// is completely meaningless, just assume the result is zero for now...
|
||||
//
|
||||
// TODO We should of course do much better, see:
|
||||
// "ARGUMENT REDUCTION FOR HUGE ARGUMENTS" K C Ng 1992
|
||||
//
|
||||
if (n_pi.compare(get_constant_one_over_epsilon<T>()) > 0)
|
||||
{
|
||||
result = ui_type(1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
eval_subtract(xx, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
|
||||
// Adjust signs if the multiple of pi is not even.
|
||||
t = ui_type(2);
|
||||
eval_fmod(t, n_pi, t);
|
||||
const bool b_n_pi_is_even = eval_get_sign(t) == 0;
|
||||
|
||||
if(!b_n_pi_is_even)
|
||||
{
|
||||
b_negate_cos = !b_negate_cos;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce the argument to 0 <= xx <= pi/2.
|
||||
eval_ldexp(t, get_constant_pi<T>(), -1);
|
||||
int com = xx.compare(t);
|
||||
if(com > 0)
|
||||
{
|
||||
eval_subtract(xx, get_constant_pi<T>(), xx);
|
||||
b_negate_cos = !b_negate_cos;
|
||||
BOOST_MATH_INSTRUMENT_CODE(xx.str(0, std::ios_base::scientific));
|
||||
}
|
||||
|
||||
const bool b_zero = eval_get_sign(xx) == 0;
|
||||
const bool b_pi_half = com == 0;
|
||||
|
||||
// Check if the reduced argument is very close to 0.
|
||||
const bool b_near_zero = xx.compare(fp_type(1e-1)) < 0;
|
||||
|
||||
if(b_zero)
|
||||
{
|
||||
result = si_type(1);
|
||||
}
|
||||
else if(b_pi_half)
|
||||
{
|
||||
result = si_type(0);
|
||||
}
|
||||
else if(b_near_zero)
|
||||
{
|
||||
eval_multiply(t, xx, xx);
|
||||
eval_divide(t, si_type(-4));
|
||||
n_pi = fp_type(0.5f);
|
||||
hyp0F1(result, n_pi, t);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result.str(0, std::ios_base::scientific));
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_subtract(t, xx);
|
||||
eval_sin(result, t);
|
||||
}
|
||||
if(b_negate_cos)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_tan(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The tan function is only valid for floating point types.");
|
||||
if(&result == &x)
|
||||
{
|
||||
T temp;
|
||||
eval_tan(temp, x);
|
||||
result = temp;
|
||||
return;
|
||||
}
|
||||
T t;
|
||||
eval_sin(result, x);
|
||||
eval_cos(t, x);
|
||||
eval_divide(result, t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hyp2F1(T& result, const T& a, const T& b, const T& c, const T& x)
|
||||
{
|
||||
// Compute the series representation of hyperg_2f1 taken from
|
||||
// Abramowitz and Stegun 15.1.1.
|
||||
// There are no checks on input range or parameter boundaries.
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
T x_pow_n_div_n_fact(x);
|
||||
T pochham_a (a);
|
||||
T pochham_b (b);
|
||||
T pochham_c (c);
|
||||
T ap (a);
|
||||
T bp (b);
|
||||
T cp (c);
|
||||
|
||||
eval_multiply(result, pochham_a, pochham_b);
|
||||
eval_divide(result, pochham_c);
|
||||
eval_multiply(result, x_pow_n_div_n_fact);
|
||||
eval_add(result, ui_type(1));
|
||||
|
||||
T lim;
|
||||
eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
|
||||
|
||||
if(eval_get_sign(lim) < 0)
|
||||
lim.negate();
|
||||
|
||||
ui_type n;
|
||||
T term;
|
||||
|
||||
const unsigned series_limit =
|
||||
boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
|
||||
? 100 : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
|
||||
// Series expansion of hyperg_2f1(a, b; c; x).
|
||||
for(n = 2; n < series_limit; ++n)
|
||||
{
|
||||
eval_multiply(x_pow_n_div_n_fact, x);
|
||||
eval_divide(x_pow_n_div_n_fact, n);
|
||||
|
||||
eval_increment(ap);
|
||||
eval_multiply(pochham_a, ap);
|
||||
eval_increment(bp);
|
||||
eval_multiply(pochham_b, bp);
|
||||
eval_increment(cp);
|
||||
eval_multiply(pochham_c, cp);
|
||||
|
||||
eval_multiply(term, pochham_a, pochham_b);
|
||||
eval_divide(term, pochham_c);
|
||||
eval_multiply(term, x_pow_n_div_n_fact);
|
||||
eval_add(result, term);
|
||||
|
||||
if(eval_get_sign(term) < 0)
|
||||
term.negate();
|
||||
if(lim.compare(term) >= 0)
|
||||
break;
|
||||
}
|
||||
if(n > series_limit)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("H2F1 failed to converge."));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_asin(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The asin function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
if(&result == &x)
|
||||
{
|
||||
T t(x);
|
||||
eval_asin(result, t);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
case FP_INFINITE:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = x;
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
const bool b_neg = eval_get_sign(x) < 0;
|
||||
|
||||
T xx(x);
|
||||
if(b_neg)
|
||||
xx.negate();
|
||||
|
||||
int c = xx.compare(ui_type(1));
|
||||
if(c > 0)
|
||||
{
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
}
|
||||
else if(c == 0)
|
||||
{
|
||||
result = get_constant_pi<T>();
|
||||
eval_ldexp(result, result, -1);
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
if(xx.compare(fp_type(1e-4)) < 0)
|
||||
{
|
||||
// http://functions.wolfram.com/ElementaryFunctions/ArcSin/26/01/01/
|
||||
eval_multiply(xx, xx);
|
||||
T t1, t2;
|
||||
t1 = fp_type(0.5f);
|
||||
t2 = fp_type(1.5f);
|
||||
hyp2F1(result, t1, t1, t2, xx);
|
||||
eval_multiply(result, x);
|
||||
return;
|
||||
}
|
||||
else if(xx.compare(fp_type(1 - 1e-4f)) > 0)
|
||||
{
|
||||
T dx1;
|
||||
T t1, t2;
|
||||
eval_subtract(dx1, ui_type(1), xx);
|
||||
t1 = fp_type(0.5f);
|
||||
t2 = fp_type(1.5f);
|
||||
eval_ldexp(dx1, dx1, -1);
|
||||
hyp2F1(result, t1, t1, t2, dx1);
|
||||
eval_ldexp(dx1, dx1, 2);
|
||||
eval_sqrt(t1, dx1);
|
||||
eval_multiply(result, t1);
|
||||
eval_ldexp(t1, get_constant_pi<T>(), -1);
|
||||
result.negate();
|
||||
eval_add(result, t1);
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
typedef typename boost::multiprecision::detail::canonical<long double, T>::type guess_type;
|
||||
#else
|
||||
typedef fp_type guess_type;
|
||||
#endif
|
||||
// Get initial estimate using standard math function asin.
|
||||
guess_type dd;
|
||||
eval_convert_to(&dd, xx);
|
||||
|
||||
result = (guess_type)(std::asin(dd));
|
||||
|
||||
// Newton-Raphson iteration, we should double our precision with each iteration,
|
||||
// in practice this seems to not quite work in all cases... so terminate when we
|
||||
// have at least 2/3 of the digits correct on the assumption that the correction
|
||||
// we've just added will finish the job...
|
||||
|
||||
boost::intmax_t current_precision = eval_ilogb(result);
|
||||
boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3;
|
||||
|
||||
// Newton-Raphson iteration
|
||||
while(current_precision > target_precision)
|
||||
{
|
||||
T sine, cosine;
|
||||
eval_sin(sine, result);
|
||||
eval_cos(cosine, result);
|
||||
eval_subtract(sine, xx);
|
||||
eval_divide(sine, cosine);
|
||||
eval_subtract(result, sine);
|
||||
current_precision = eval_ilogb(sine);
|
||||
if(current_precision <= (std::numeric_limits<typename T::exponent_type>::min)() + 1)
|
||||
break;
|
||||
}
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void eval_acos(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The acos function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
case FP_INFINITE:
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = get_constant_pi<T>();
|
||||
eval_ldexp(result, result, -1); // divide by two.
|
||||
return;
|
||||
}
|
||||
|
||||
eval_abs(result, x);
|
||||
int c = result.compare(ui_type(1));
|
||||
|
||||
if(c > 0)
|
||||
{
|
||||
if(std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
|
||||
{
|
||||
result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
|
||||
errno = EDOM;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::domain_error("Result is undefined or complex and there is no NaN for this number type."));
|
||||
return;
|
||||
}
|
||||
else if(c == 0)
|
||||
{
|
||||
if(eval_get_sign(x) < 0)
|
||||
result = get_constant_pi<T>();
|
||||
else
|
||||
result = ui_type(0);
|
||||
return;
|
||||
}
|
||||
|
||||
eval_asin(result, x);
|
||||
T t;
|
||||
eval_ldexp(t, get_constant_pi<T>(), -1);
|
||||
eval_subtract(result, t);
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_atan(T& result, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan function is only valid for floating point types.");
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::int32_t, T>::type si_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
typedef typename mpl::front<typename T::float_types>::type fp_type;
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = x;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
result = x;
|
||||
return;
|
||||
case FP_INFINITE:
|
||||
if(eval_get_sign(x) < 0)
|
||||
{
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
return;
|
||||
default: ;
|
||||
}
|
||||
|
||||
const bool b_neg = eval_get_sign(x) < 0;
|
||||
|
||||
T xx(x);
|
||||
if(b_neg)
|
||||
xx.negate();
|
||||
|
||||
if(xx.compare(fp_type(0.1)) < 0)
|
||||
{
|
||||
T t1, t2, t3;
|
||||
t1 = ui_type(1);
|
||||
t2 = fp_type(0.5f);
|
||||
t3 = fp_type(1.5f);
|
||||
eval_multiply(xx, xx);
|
||||
xx.negate();
|
||||
hyp2F1(result, t1, t2, t3, xx);
|
||||
eval_multiply(result, x);
|
||||
return;
|
||||
}
|
||||
|
||||
if(xx.compare(fp_type(10)) > 0)
|
||||
{
|
||||
T t1, t2, t3;
|
||||
t1 = fp_type(0.5f);
|
||||
t2 = ui_type(1u);
|
||||
t3 = fp_type(1.5f);
|
||||
eval_multiply(xx, xx);
|
||||
eval_divide(xx, si_type(-1), xx);
|
||||
hyp2F1(result, t1, t2, t3, xx);
|
||||
eval_divide(result, x);
|
||||
if(!b_neg)
|
||||
result.negate();
|
||||
eval_ldexp(t1, get_constant_pi<T>(), -1);
|
||||
eval_add(result, t1);
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get initial estimate using standard math function atan.
|
||||
fp_type d;
|
||||
eval_convert_to(&d, xx);
|
||||
result = fp_type(std::atan(d));
|
||||
|
||||
// Newton-Raphson iteration, we should double our precision with each iteration,
|
||||
// in practice this seems to not quite work in all cases... so terminate when we
|
||||
// have at least 2/3 of the digits correct on the assumption that the correction
|
||||
// we've just added will finish the job...
|
||||
|
||||
boost::intmax_t current_precision = eval_ilogb(result);
|
||||
boost::intmax_t target_precision = current_precision - 1 - (std::numeric_limits<number<T> >::digits * 2) / 3;
|
||||
|
||||
T s, c, t;
|
||||
while(current_precision > target_precision)
|
||||
{
|
||||
eval_sin(s, result);
|
||||
eval_cos(c, result);
|
||||
eval_multiply(t, xx, c);
|
||||
eval_subtract(t, s);
|
||||
eval_multiply(s, t, c);
|
||||
eval_add(result, s);
|
||||
current_precision = eval_ilogb(s);
|
||||
if(current_precision <= (std::numeric_limits<typename T::exponent_type>::min)() + 1)
|
||||
break;
|
||||
}
|
||||
if(b_neg)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void eval_atan2(T& result, const T& y, const T& x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(number_category<T>::value == number_kind_floating_point, "The atan2 function is only valid for floating point types.");
|
||||
if(&result == &y)
|
||||
{
|
||||
T temp(y);
|
||||
eval_atan2(result, temp, x);
|
||||
return;
|
||||
}
|
||||
else if(&result == &x)
|
||||
{
|
||||
T temp(x);
|
||||
eval_atan2(result, y, temp);
|
||||
return;
|
||||
}
|
||||
|
||||
typedef typename boost::multiprecision::detail::canonical<boost::uint32_t, T>::type ui_type;
|
||||
|
||||
switch(eval_fpclassify(y))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = y;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
{
|
||||
if(eval_signbit(x))
|
||||
{
|
||||
result = get_constant_pi<T>();
|
||||
if(eval_signbit(y))
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = y; // Note we allow atan2(0,0) to be +-zero, even though it's mathematically undefined
|
||||
}
|
||||
return;
|
||||
}
|
||||
case FP_INFINITE:
|
||||
{
|
||||
if(eval_fpclassify(x) == FP_INFINITE)
|
||||
{
|
||||
if(eval_signbit(x))
|
||||
{
|
||||
// 3Pi/4
|
||||
eval_ldexp(result, get_constant_pi<T>(), -2);
|
||||
eval_subtract(result, get_constant_pi<T>());
|
||||
if(eval_get_sign(y) >= 0)
|
||||
result.negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pi/4
|
||||
eval_ldexp(result, get_constant_pi<T>(), -2);
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(eval_fpclassify(x))
|
||||
{
|
||||
case FP_NAN:
|
||||
result = x;
|
||||
errno = EDOM;
|
||||
return;
|
||||
case FP_ZERO:
|
||||
{
|
||||
eval_ldexp(result, get_constant_pi<T>(), -1);
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
case FP_INFINITE:
|
||||
if(eval_get_sign(x) > 0)
|
||||
result = ui_type(0);
|
||||
else
|
||||
result = get_constant_pi<T>();
|
||||
if(eval_get_sign(y) < 0)
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
T xx;
|
||||
eval_divide(xx, y, x);
|
||||
if(eval_get_sign(xx) < 0)
|
||||
xx.negate();
|
||||
|
||||
eval_atan(result, xx);
|
||||
|
||||
// Determine quadrant (sign) based on signs of x, y
|
||||
const bool y_neg = eval_get_sign(y) < 0;
|
||||
const bool x_neg = eval_get_sign(x) < 0;
|
||||
|
||||
if(y_neg != x_neg)
|
||||
result.negate();
|
||||
|
||||
if(x_neg)
|
||||
{
|
||||
if(y_neg)
|
||||
eval_subtract(result, get_constant_pi<T>());
|
||||
else
|
||||
eval_add(result, get_constant_pi<T>());
|
||||
}
|
||||
}
|
||||
template<class T, class A>
|
||||
inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(T& result, const T& x, const A& a)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
|
||||
typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
|
||||
cast_type c;
|
||||
c = a;
|
||||
eval_atan2(result, x, c);
|
||||
}
|
||||
|
||||
template<class T, class A>
|
||||
inline typename enable_if<is_arithmetic<A>, void>::type eval_atan2(T& result, const A& x, const T& a)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<A, T>::type canonical_type;
|
||||
typedef typename mpl::if_<is_same<A, canonical_type>, T, canonical_type>::type cast_type;
|
||||
cast_type c;
|
||||
c = x;
|
||||
eval_atan2(result, c, a);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -0,0 +1,590 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_MP_GENERIC_INTERCONVERT_HPP
|
||||
#define BOOST_MP_GENERIC_INTERCONVERT_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/default_ops.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127 6326)
|
||||
#endif
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
template <class To, class From>
|
||||
inline To do_cast(const From & from)
|
||||
{
|
||||
return static_cast<To>(from);
|
||||
}
|
||||
template <class To, class B, ::boost::multiprecision::expression_template_option et>
|
||||
inline To do_cast(const number<B, et>& from)
|
||||
{
|
||||
return from.template convert_to<To>();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_bitwise_and;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_right_shift;
|
||||
using default_ops::eval_ldexp;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_is_zero;
|
||||
// smallest unsigned type handled natively by "From" is likely to be it's limb_type:
|
||||
typedef typename canonical<unsigned char, From>::type l_limb_type;
|
||||
// get the corresponding type that we can assign to "To":
|
||||
typedef typename canonical<l_limb_type, To>::type to_type;
|
||||
From t(from);
|
||||
bool is_neg = eval_get_sign(t) < 0;
|
||||
if(is_neg)
|
||||
t.negate();
|
||||
// Pick off the first limb:
|
||||
l_limb_type limb;
|
||||
l_limb_type mask = static_cast<l_limb_type>(~static_cast<l_limb_type>(0));
|
||||
From fl;
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
to = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<l_limb_type>::digits);
|
||||
//
|
||||
// Then keep picking off more limbs until "t" is zero:
|
||||
//
|
||||
To l;
|
||||
unsigned shift = std::numeric_limits<l_limb_type>::digits;
|
||||
while(!eval_is_zero(t))
|
||||
{
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
l = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<l_limb_type>::digits);
|
||||
eval_ldexp(l, l, shift);
|
||||
eval_add(to, l);
|
||||
shift += std::numeric_limits<l_limb_type>::digits;
|
||||
}
|
||||
//
|
||||
// Finish off by setting the sign:
|
||||
//
|
||||
if(is_neg)
|
||||
to.negate();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_bitwise_and;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_right_shift;
|
||||
using default_ops::eval_left_shift;
|
||||
using default_ops::eval_bitwise_or;
|
||||
using default_ops::eval_is_zero;
|
||||
// smallest unsigned type handled natively by "From" is likely to be it's limb_type:
|
||||
typedef typename canonical<unsigned char, From>::type limb_type;
|
||||
// get the corresponding type that we can assign to "To":
|
||||
typedef typename canonical<limb_type, To>::type to_type;
|
||||
From t(from);
|
||||
bool is_neg = eval_get_sign(t) < 0;
|
||||
if(is_neg)
|
||||
t.negate();
|
||||
// Pick off the first limb:
|
||||
limb_type limb;
|
||||
limb_type mask = static_cast<limb_type>(~static_cast<limb_type>(0));
|
||||
From fl;
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
to = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
||||
//
|
||||
// Then keep picking off more limbs until "t" is zero:
|
||||
//
|
||||
To l;
|
||||
unsigned shift = std::numeric_limits<limb_type>::digits;
|
||||
while(!eval_is_zero(t))
|
||||
{
|
||||
eval_bitwise_and(fl, t, mask);
|
||||
eval_convert_to(&limb, fl);
|
||||
l = static_cast<to_type>(limb);
|
||||
eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
||||
eval_left_shift(l, shift);
|
||||
eval_bitwise_or(to, l);
|
||||
shift += std::numeric_limits<limb_type>::digits;
|
||||
}
|
||||
//
|
||||
// Finish off by setting the sign:
|
||||
//
|
||||
if(is_neg)
|
||||
to.negate();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
//
|
||||
// The code here only works when the radix of "From" is 2, we could try shifting by other
|
||||
// radixes but it would complicate things.... use a string conversion when the radix is other
|
||||
// than 2:
|
||||
//
|
||||
if(std::numeric_limits<number<From> >::radix != 2)
|
||||
{
|
||||
to = from.str(0, std::ios_base::fmtflags()).c_str();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
typedef typename canonical<unsigned char, To>::type ui_type;
|
||||
|
||||
using default_ops::eval_fpclassify;
|
||||
using default_ops::eval_add;
|
||||
using default_ops::eval_subtract;
|
||||
using default_ops::eval_convert_to;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_is_zero;
|
||||
|
||||
//
|
||||
// First classify the input, then handle the special cases:
|
||||
//
|
||||
int c = eval_fpclassify(from);
|
||||
|
||||
if(c == (int)FP_ZERO)
|
||||
{
|
||||
to = ui_type(0);
|
||||
return;
|
||||
}
|
||||
else if(c == (int)FP_NAN)
|
||||
{
|
||||
to = static_cast<const char*>("nan");
|
||||
return;
|
||||
}
|
||||
else if(c == (int)FP_INFINITE)
|
||||
{
|
||||
to = static_cast<const char*>("inf");
|
||||
if(eval_get_sign(from) < 0)
|
||||
to.negate();
|
||||
return;
|
||||
}
|
||||
|
||||
typename From::exponent_type e;
|
||||
From f, term;
|
||||
to = ui_type(0);
|
||||
|
||||
eval_frexp(f, from, &e);
|
||||
|
||||
static const int shift = std::numeric_limits<boost::intmax_t>::digits - 1;
|
||||
|
||||
while(!eval_is_zero(f))
|
||||
{
|
||||
// extract int sized bits from f:
|
||||
eval_ldexp(f, f, shift);
|
||||
eval_floor(term, f);
|
||||
e -= shift;
|
||||
eval_ldexp(to, to, shift);
|
||||
typename boost::multiprecision::detail::canonical<boost::intmax_t, To>::type ll;
|
||||
eval_convert_to(&ll, term);
|
||||
eval_add(to, ll);
|
||||
eval_subtract(f, term);
|
||||
}
|
||||
typedef typename To::exponent_type to_exponent;
|
||||
if((e > (std::numeric_limits<to_exponent>::max)()) || (e < (std::numeric_limits<to_exponent>::min)()))
|
||||
{
|
||||
to = static_cast<const char*>("inf");
|
||||
if(eval_get_sign(from) < 0)
|
||||
to.negate();
|
||||
return;
|
||||
}
|
||||
eval_ldexp(to, to, static_cast<to_exponent>(e));
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
||||
{
|
||||
typedef typename component_type<number<To> >::type to_component_type;
|
||||
|
||||
number<From> t(from);
|
||||
to_component_type n(numerator(t)), d(denominator(t));
|
||||
using default_ops::assign_components;
|
||||
assign_components(to, n.backend(), d.backend());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
||||
{
|
||||
typedef typename component_type<number<To> >::type to_component_type;
|
||||
|
||||
number<From> t(from);
|
||||
to_component_type n(t), d(1);
|
||||
using default_ops::assign_components;
|
||||
assign_components(to, n.backend(), d.backend());
|
||||
}
|
||||
|
||||
template <class R, class LargeInteger>
|
||||
R safe_convert_to_float(const LargeInteger& i)
|
||||
{
|
||||
using std::ldexp;
|
||||
if(!i)
|
||||
return R(0);
|
||||
if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::max_exponent)
|
||||
{
|
||||
LargeInteger val(i);
|
||||
if(val.sign() < 0)
|
||||
val = -val;
|
||||
unsigned mb = msb(val);
|
||||
if(mb >= std::numeric_limits<R>::max_exponent)
|
||||
{
|
||||
int scale_factor = (int)mb + 1 - std::numeric_limits<R>::max_exponent;
|
||||
BOOST_ASSERT(scale_factor >= 1);
|
||||
val >>= scale_factor;
|
||||
R result = val.template convert_to<R>();
|
||||
if(std::numeric_limits<R>::digits == 0 || std::numeric_limits<R>::digits >= std::numeric_limits<R>::max_exponent)
|
||||
{
|
||||
//
|
||||
// Calculate and add on the remainder, only if there are more
|
||||
// digits in the mantissa that the size of the exponent, in
|
||||
// other words if we are dropping digits in the conversion
|
||||
// otherwise:
|
||||
//
|
||||
LargeInteger remainder(i);
|
||||
remainder &= (LargeInteger(1) << scale_factor) - 1;
|
||||
result += ldexp(safe_convert_to_float<R>(remainder), -scale_factor);
|
||||
}
|
||||
return i.sign() < 0 ? static_cast<R>(-result) : result;
|
||||
}
|
||||
}
|
||||
return i.template convert_to<R>();
|
||||
}
|
||||
|
||||
template <class To, class Integer>
|
||||
inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&)
|
||||
{
|
||||
//
|
||||
// If we get here, then there's something about one type or the other
|
||||
// that prevents an exactly rounded result from being calculated
|
||||
// (or at least it's not clear how to implement such a thing).
|
||||
//
|
||||
using default_ops::eval_divide;
|
||||
number<To> fn(safe_convert_to_float<number<To> >(n)), fd(safe_convert_to_float<number<To> >(d));
|
||||
eval_divide(result, fn.backend(), fd.backend());
|
||||
}
|
||||
template <class To, class Integer>
|
||||
inline typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&)
|
||||
{
|
||||
//
|
||||
// If we get here, then there's something about one type or the other
|
||||
// that prevents an exactly rounded result from being calculated
|
||||
// (or at least it's not clear how to implement such a thing).
|
||||
//
|
||||
To fd(safe_convert_to_float<To>(d));
|
||||
result = safe_convert_to_float<To>(n);
|
||||
result /= fd;
|
||||
}
|
||||
|
||||
template <class To, class Integer>
|
||||
typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_&)
|
||||
{
|
||||
//
|
||||
// If we get here, then the precision of type To is known, and the integer type is unbounded
|
||||
// so we can use integer division plus manipulation of the remainder to get an exactly
|
||||
// rounded result.
|
||||
//
|
||||
if(num == 0)
|
||||
{
|
||||
result = 0;
|
||||
return;
|
||||
}
|
||||
bool s = false;
|
||||
if(num < 0)
|
||||
{
|
||||
s = true;
|
||||
num = -num;
|
||||
}
|
||||
int denom_bits = msb(denom);
|
||||
int shift = std::numeric_limits<To>::digits + denom_bits - msb(num);
|
||||
if(shift > 0)
|
||||
num <<= shift;
|
||||
else if(shift < 0)
|
||||
denom <<= boost::multiprecision::detail::unsigned_abs(shift);
|
||||
Integer q, r;
|
||||
divide_qr(num, denom, q, r);
|
||||
int q_bits = msb(q);
|
||||
if(q_bits == std::numeric_limits<To>::digits - 1)
|
||||
{
|
||||
//
|
||||
// Round up if 2 * r > denom:
|
||||
//
|
||||
r <<= 1;
|
||||
int c = r.compare(denom);
|
||||
if(c > 0)
|
||||
++q;
|
||||
else if((c == 0) && (q & 1u))
|
||||
{
|
||||
++q;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(q_bits == std::numeric_limits<To>::digits);
|
||||
//
|
||||
// We basically already have the rounding info:
|
||||
//
|
||||
if(q & 1u)
|
||||
{
|
||||
if(r || (q & 2u))
|
||||
++q;
|
||||
}
|
||||
}
|
||||
using std::ldexp;
|
||||
result = do_cast<To>(q);
|
||||
result = ldexp(result, -shift);
|
||||
if(s)
|
||||
result = -result;
|
||||
}
|
||||
template <class To, class Integer>
|
||||
inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
|
||||
generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_& tag)
|
||||
{
|
||||
number<To> t;
|
||||
generic_convert_rational_to_float_imp(t, num, denom, tag);
|
||||
result = t.backend();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
inline void generic_convert_rational_to_float(To& result, const From& f)
|
||||
{
|
||||
//
|
||||
// Type From is always a Backend to number<>, or an
|
||||
// instance of number<>, but we allow
|
||||
// To to be either a Backend type, or a real number type,
|
||||
// that way we can call this from generic conversions, and
|
||||
// from specific conversions to built in types.
|
||||
//
|
||||
typedef typename mpl::if_c<is_number<From>::value, From, number<From> >::type actual_from_type;
|
||||
typedef typename mpl::if_c<is_number<To>::value || is_floating_point<To>::value, To, number<To> >::type actual_to_type;
|
||||
typedef typename component_type<actual_from_type>::type integer_type;
|
||||
typedef mpl::bool_<!std::numeric_limits<integer_type>::is_specialized
|
||||
|| std::numeric_limits<integer_type>::is_bounded
|
||||
|| !std::numeric_limits<actual_to_type>::is_specialized
|
||||
|| !std::numeric_limits<actual_to_type>::is_bounded
|
||||
|| (std::numeric_limits<actual_to_type>::radix != 2)> dispatch_tag;
|
||||
|
||||
integer_type n(numerator(static_cast<actual_from_type>(f))), d(denominator(static_cast<actual_from_type>(f)));
|
||||
generic_convert_rational_to_float_imp(result, n, d, dispatch_tag());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
inline void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
||||
{
|
||||
generic_convert_rational_to_float(to, from);
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/)
|
||||
{
|
||||
typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
|
||||
static const int shift = std::numeric_limits<boost::long_long_type>::digits;
|
||||
typename From::exponent_type e;
|
||||
typename component_type<number<To> >::type num, denom;
|
||||
number<From> val(from);
|
||||
val = frexp(val, &e);
|
||||
while(val)
|
||||
{
|
||||
val = ldexp(val, shift);
|
||||
e -= shift;
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
num <<= shift;
|
||||
num += ll;
|
||||
}
|
||||
denom = ui_type(1u);
|
||||
if(e < 0)
|
||||
denom <<= -e;
|
||||
else if(e > 0)
|
||||
num <<= e;
|
||||
assign_components(to, num.backend(), denom.backend());
|
||||
}
|
||||
|
||||
template <class To, class From, int Radix>
|
||||
void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<Radix>& /*radix*/)
|
||||
{
|
||||
//
|
||||
// This is almost the same as the binary case above, but we have to use
|
||||
// scalbn and ilogb rather than ldexp and frexp, we also only extract
|
||||
// one Radix digit at a time which is terribly inefficient!
|
||||
//
|
||||
typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
|
||||
typename From::exponent_type e;
|
||||
typename component_type<number<To> >::type num, denom;
|
||||
number<From> val(from);
|
||||
|
||||
if (!val)
|
||||
{
|
||||
to = ui_type(0u);
|
||||
return;
|
||||
}
|
||||
|
||||
e = ilogb(val);
|
||||
val = scalbn(val, -e);
|
||||
while(val)
|
||||
{
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
val = scalbn(val, 1);
|
||||
num *= Radix;
|
||||
num += ll;
|
||||
--e;
|
||||
}
|
||||
++e;
|
||||
denom = ui_type(Radix);
|
||||
denom = pow(denom, abs(e));
|
||||
if(e > 0)
|
||||
{
|
||||
num *= denom;
|
||||
denom = 1;
|
||||
}
|
||||
assign_components(to, num.backend(), denom.backend());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
||||
{
|
||||
generic_interconvert_float2rational(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
||||
{
|
||||
number<From> t(from);
|
||||
number<To> result(numerator(t) / denominator(t));
|
||||
to = result.backend();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<2>& /*radix*/)
|
||||
{
|
||||
typedef typename From::exponent_type exponent_type;
|
||||
static const exponent_type shift = std::numeric_limits<boost::long_long_type>::digits;
|
||||
exponent_type e;
|
||||
number<To> num(0u);
|
||||
number<From> val(from);
|
||||
val = frexp(val, &e);
|
||||
while(e > 0)
|
||||
{
|
||||
int s = (std::min)(e, shift);
|
||||
val = ldexp(val, s);
|
||||
e -= s;
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
num <<= s;
|
||||
num += ll;
|
||||
}
|
||||
to = num.backend();
|
||||
}
|
||||
|
||||
template <class To, class From, int Radix>
|
||||
void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<Radix>& /*radix*/)
|
||||
{
|
||||
//
|
||||
// This is almost the same as the binary case above, but we have to use
|
||||
// scalbn and ilogb rather than ldexp and frexp, we also only extract
|
||||
// one Radix digit at a time which is terribly inefficient!
|
||||
//
|
||||
typename From::exponent_type e;
|
||||
number<To> num(0u);
|
||||
number<From> val(from);
|
||||
e = ilogb(val);
|
||||
val = scalbn(val, -e);
|
||||
while(e >= 0)
|
||||
{
|
||||
boost::long_long_type ll = boost::math::lltrunc(val);
|
||||
val -= ll;
|
||||
val = scalbn(val, 1);
|
||||
num *= Radix;
|
||||
num += ll;
|
||||
--e;
|
||||
}
|
||||
to = num.backend();
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
||||
{
|
||||
generic_interconvert_float2int(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
|
||||
}
|
||||
|
||||
template <class To, class From, class tag>
|
||||
void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::true_&, const tag&)
|
||||
{
|
||||
// We just want the real part, and "to" is the correct type already:
|
||||
eval_real(to, from);
|
||||
|
||||
To im;
|
||||
eval_imag(im, from);
|
||||
if(!eval_is_zero(im))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar."));
|
||||
}
|
||||
template <class To, class From>
|
||||
void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::false_&, const mpl::true_&)
|
||||
{
|
||||
typedef typename component_type<number<From> >::type component_number;
|
||||
typedef typename component_number::backend_type component_backend;
|
||||
//
|
||||
// Get the real part and copy-construct the result from it:
|
||||
//
|
||||
component_backend r;
|
||||
generic_interconvert_complex_to_scalar(r, from, mpl::true_(), mpl::true_());
|
||||
to = r;
|
||||
}
|
||||
template <class To, class From>
|
||||
void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::false_&, const mpl::false_&)
|
||||
{
|
||||
typedef typename component_type<number<From> >::type component_number;
|
||||
typedef typename component_number::backend_type component_backend;
|
||||
//
|
||||
// Get the real part and use a generic_interconvert to type To:
|
||||
//
|
||||
component_backend r;
|
||||
generic_interconvert_complex_to_scalar(r, from, mpl::true_(), mpl::true_());
|
||||
generic_interconvert(to, r, mpl::int_<number_category<To>::value>(), mpl::int_<number_category<To>::value>());
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_complex>& /*from_type*/)
|
||||
{
|
||||
typedef typename component_type<number<From> >::type component_number;
|
||||
typedef typename component_number::backend_type component_backend;
|
||||
|
||||
generic_interconvert_complex_to_scalar(to, from, mpl::bool_<boost::is_same<component_backend, To>::value>(), mpl::bool_<boost::is_constructible<To, const component_backend&>::value>());
|
||||
}
|
||||
template <class To, class From>
|
||||
void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_complex>& /*from_type*/)
|
||||
{
|
||||
typedef typename component_type<number<From> >::type component_number;
|
||||
typedef typename component_number::backend_type component_backend;
|
||||
|
||||
generic_interconvert_complex_to_scalar(to, from, mpl::bool_<boost::is_same<component_backend, To>::value>(), mpl::bool_<boost::is_constructible<To, const component_backend&>::value>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespaces
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MP_GENERIC_INTERCONVERT_HPP
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_INT_FUNC_HPP
|
||||
#define BOOST_MP_INT_FUNC_HPP
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace default_ops
|
||||
{
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_qr(const Backend& x, const Backend& y, Backend& q, Backend& r)
|
||||
{
|
||||
eval_divide(q, x, y);
|
||||
eval_modulus(r, x, y);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
inline Integer eval_integer_modulus(const Backend& x, Integer val)
|
||||
{
|
||||
BOOST_MP_USING_ABS
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_convert_to;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type int_type;
|
||||
Backend t;
|
||||
eval_modulus(t, x, static_cast<int_type>(val));
|
||||
Integer result;
|
||||
eval_convert_to(&result, t);
|
||||
return abs(result);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
|
||||
template <class B>
|
||||
inline void eval_gcd(B& result, const B& a, const B& b)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
int shift;
|
||||
|
||||
B u(a), v(b);
|
||||
|
||||
int s = eval_get_sign(u);
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if(s < 0)
|
||||
{
|
||||
u.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
s = eval_get_sign(v);
|
||||
if(s < 0)
|
||||
{
|
||||
v.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
|
||||
unsigned us = eval_lsb(u);
|
||||
unsigned vs = eval_lsb(v);
|
||||
shift = (std::min)(us, vs);
|
||||
eval_right_shift(u, us);
|
||||
eval_right_shift(v, vs);
|
||||
|
||||
do
|
||||
{
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
s = u.compare(v);
|
||||
if(s > 0)
|
||||
u.swap(v);
|
||||
if(s == 0)
|
||||
break;
|
||||
eval_subtract(v, u);
|
||||
vs = eval_lsb(v);
|
||||
eval_right_shift(v, vs);
|
||||
}
|
||||
while(true);
|
||||
|
||||
result = u;
|
||||
eval_left_shift(result, shift);
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class B>
|
||||
inline void eval_lcm(B& result, const B& a, const B& b)
|
||||
{
|
||||
typedef typename mpl::front<typename B::unsigned_types>::type ui_type;
|
||||
B t;
|
||||
eval_gcd(t, a, b);
|
||||
|
||||
if(eval_is_zero(t))
|
||||
{
|
||||
result = static_cast<ui_type>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_divide(result, a, t);
|
||||
eval_multiply(result, b);
|
||||
}
|
||||
if(eval_get_sign(result) < 0)
|
||||
result.negate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const number<Backend, ExpressionTemplates>& x, const number<Backend, ExpressionTemplates>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
using default_ops::eval_qr;
|
||||
eval_qr(x.backend(), y.backend(), q.backend(), r.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const number<Backend, ExpressionTemplates>& x, const multiprecision::detail::expression<tag, A1, A2, A3, A4>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
divide_qr(x, number<Backend, ExpressionTemplates>(y), q, r);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const number<Backend, ExpressionTemplates>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
divide_qr(number<Backend, ExpressionTemplates>(x), y, q, r);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer>::type
|
||||
divide_qr(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, const multiprecision::detail::expression<tagb, A1b, A2b, A3b, A4b>& y,
|
||||
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r)
|
||||
{
|
||||
divide_qr(number<Backend, ExpressionTemplates>(x), number<Backend, ExpressionTemplates>(y), q, r);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Integer>
|
||||
inline typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<Backend>::value == number_kind_integer> >, Integer>::type
|
||||
integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
|
||||
{
|
||||
using default_ops::eval_integer_modulus;
|
||||
return eval_integer_modulus(x.backend(), val);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Integer>
|
||||
inline typename enable_if<mpl::and_<is_integral<Integer>, mpl::bool_<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer> >, Integer>::type
|
||||
integer_modulus(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, Integer val)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type result_type;
|
||||
return integer_modulus(result_type(x), val);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
|
||||
lsb(const number<Backend, ExpressionTemplates>& x)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
return eval_lsb(x.backend());
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
|
||||
lsb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
||||
number_type n(x);
|
||||
using default_ops::eval_lsb;
|
||||
return eval_lsb(n.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, unsigned>::type
|
||||
msb(const number<Backend, ExpressionTemplates>& x)
|
||||
{
|
||||
using default_ops::eval_msb;
|
||||
return eval_msb(x.backend());
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, unsigned>::type
|
||||
msb(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
||||
number_type n(x);
|
||||
using default_ops::eval_msb;
|
||||
return eval_msb(n.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, bool>::type
|
||||
bit_test(const number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_test;
|
||||
return eval_bit_test(x.backend(), index);
|
||||
}
|
||||
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<number_category<typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type>::value == number_kind_integer, bool>::type
|
||||
bit_test(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, unsigned index)
|
||||
{
|
||||
typedef typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type number_type;
|
||||
number_type n(x);
|
||||
using default_ops::eval_bit_test;
|
||||
return eval_bit_test(n.backend(), index);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
||||
bit_set(number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_set;
|
||||
eval_bit_set(x.backend(), index);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
||||
bit_unset(number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_unset;
|
||||
eval_bit_unset(x.backend(), index);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<number_category<Backend>::value == number_kind_integer, number<Backend, ExpressionTemplates>&>::type
|
||||
bit_flip(number<Backend, ExpressionTemplates>& x, unsigned index)
|
||||
{
|
||||
using default_ops::eval_bit_flip;
|
||||
eval_bit_flip(x.backend(), index);
|
||||
return x;
|
||||
}
|
||||
|
||||
namespace default_ops{
|
||||
|
||||
//
|
||||
// Within powm, we need a type with twice as many digits as the argument type, define
|
||||
// a traits class to obtain that type:
|
||||
//
|
||||
template <class Backend>
|
||||
struct double_precision_type
|
||||
{
|
||||
typedef Backend type;
|
||||
};
|
||||
|
||||
//
|
||||
// If the exponent is a signed integer type, then we need to
|
||||
// check the value is positive:
|
||||
//
|
||||
template <class Backend>
|
||||
inline void check_sign_of_backend(const Backend& v, const mpl::true_)
|
||||
{
|
||||
if(eval_get_sign(v) < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
}
|
||||
template <class Backend>
|
||||
inline void check_sign_of_backend(const Backend&, const mpl::false_){}
|
||||
//
|
||||
// Calculate (a^p)%c:
|
||||
//
|
||||
template <class Backend>
|
||||
void eval_powm(Backend& result, const Backend& a, const Backend& p, const Backend& c)
|
||||
{
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
|
||||
check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
|
||||
|
||||
double_type x, y(a), b(p), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(eval_get_sign(b) > 0)
|
||||
{
|
||||
if(eval_bit_test(b, 0))
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, c);
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, c);
|
||||
eval_right_shift(b, ui_type(1));
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, c);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
void eval_powm(Backend& result, const Backend& a, const Backend& p, Integer c)
|
||||
{
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer, double_type>::type i1_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer, Backend>::type i2_type;
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
check_sign_of_backend(p, mpl::bool_<std::numeric_limits<number<Backend> >::is_signed>());
|
||||
|
||||
if(eval_get_sign(p) < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
|
||||
double_type x, y(a), b(p), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(eval_get_sign(b) > 0)
|
||||
{
|
||||
if(eval_bit_test(b, 0))
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, static_cast<i1_type>(c));
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, static_cast<i1_type>(c));
|
||||
eval_right_shift(b, ui_type(1));
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, static_cast<i2_type>(c));
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
typename enable_if<is_unsigned<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
|
||||
{
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
double_type x, y(a), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(b > 0)
|
||||
{
|
||||
if(b & 1)
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, c);
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, c);
|
||||
b >>= 1;
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, c);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer>
|
||||
typename enable_if<is_signed<Integer> >::type eval_powm(Backend& result, const Backend& a, Integer b, const Backend& c)
|
||||
{
|
||||
if(b < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
eval_powm(result, a, static_cast<typename make_unsigned<Integer>::type>(b), c);
|
||||
}
|
||||
|
||||
template <class Backend, class Integer1, class Integer2>
|
||||
typename enable_if<is_unsigned<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
|
||||
{
|
||||
typedef typename double_precision_type<Backend>::type double_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<unsigned char, double_type>::type ui_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer1, double_type>::type i1_type;
|
||||
typedef typename boost::multiprecision::detail::canonical<Integer2, Backend>::type i2_type;
|
||||
|
||||
using default_ops::eval_bit_test;
|
||||
using default_ops::eval_get_sign;
|
||||
using default_ops::eval_multiply;
|
||||
using default_ops::eval_modulus;
|
||||
using default_ops::eval_right_shift;
|
||||
|
||||
double_type x, y(a), t;
|
||||
x = ui_type(1u);
|
||||
|
||||
while(b > 0)
|
||||
{
|
||||
if(b & 1)
|
||||
{
|
||||
eval_multiply(t, x, y);
|
||||
eval_modulus(x, t, static_cast<i1_type>(c));
|
||||
}
|
||||
eval_multiply(t, y, y);
|
||||
eval_modulus(y, t, static_cast<i1_type>(c));
|
||||
b >>= 1;
|
||||
}
|
||||
Backend x2(x);
|
||||
eval_modulus(result, x2, static_cast<i2_type>(c));
|
||||
}
|
||||
|
||||
template <class Backend, class Integer1, class Integer2>
|
||||
typename enable_if<is_signed<Integer1> >::type eval_powm(Backend& result, const Backend& a, Integer1 b, Integer2 c)
|
||||
{
|
||||
if(b < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
eval_powm(result, a, static_cast<typename make_unsigned<Integer1>::type>(b), c);
|
||||
}
|
||||
|
||||
struct powm_func
|
||||
{
|
||||
template <class T, class U, class V>
|
||||
void operator()(T& result, const T& b, const U& p, const V& m)const
|
||||
{
|
||||
eval_powm(result, b, p, m);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class T, class U, class V>
|
||||
inline typename enable_if<
|
||||
mpl::and_<
|
||||
mpl::bool_<number_category<T>::value == number_kind_integer>,
|
||||
mpl::or_<
|
||||
is_number<T>,
|
||||
is_number_expression<T>
|
||||
>,
|
||||
mpl::or_<
|
||||
is_number<U>,
|
||||
is_number_expression<U>,
|
||||
is_integral<U>
|
||||
>,
|
||||
mpl::or_<
|
||||
is_number<V>,
|
||||
is_number_expression<V>,
|
||||
is_integral<V>
|
||||
>
|
||||
>,
|
||||
typename mpl::if_<
|
||||
is_no_et_number<T>,
|
||||
T,
|
||||
typename mpl::if_<
|
||||
is_no_et_number<U>,
|
||||
U,
|
||||
typename mpl::if_<
|
||||
is_no_et_number<V>,
|
||||
V,
|
||||
detail::expression<detail::function, default_ops::powm_func, T, U, V> >::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
powm(const T& b, const U& p, const V& mod)
|
||||
{
|
||||
return detail::expression<detail::function, default_ops::powm_func, T, U, V>(
|
||||
default_ops::powm_func(), b, p, mod);
|
||||
}
|
||||
|
||||
}} //namespaces
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2016 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_MP_MIN_MAX_HPP
|
||||
#define BOOST_MP_MIN_MAX_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/is_backend.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
//
|
||||
// Expression template overloads for (min) and (max):
|
||||
//
|
||||
// Introduced in response to https://svn.boost.org/trac/boost/ticket/11149
|
||||
// note that these can not legally be injected into namespace std, and that doing so
|
||||
// may break future enhancements to the standard. None the less adding
|
||||
// namespace std{ using boost::multiprecision::(min); using boost::multiprecision::(max); }
|
||||
// to your code may get some generic code working that wouldn't work otherwise.
|
||||
//
|
||||
// The use of enable_if on the return type is to avoid poisoning std::min/max,
|
||||
// otherwise attempting to make an explicit call to min<long>(a, b) when these and std
|
||||
// versions are in scope, will cause the compiler to try to instantiate the signatures
|
||||
// for our versions as well as the std ones, which in turn instantiates number<long>
|
||||
// which fails to compile as "long" is not a valid backend type.
|
||||
//
|
||||
template <class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on>&>::type
|
||||
(min)(const number<Backend, et_on>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
template <class Backend, class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(min)(const number<Backend, et_on>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
number<Backend, et_on> t(b);
|
||||
if(a < t)
|
||||
return a;
|
||||
return BOOST_MP_MOVE(t);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(min)(const detail::expression<tag, A1, A2, A3, A4>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
number<Backend, et_on> t(a);
|
||||
if(t < b)
|
||||
return BOOST_MP_MOVE(t);
|
||||
return b;
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type
|
||||
(min)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 < t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type (min)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 < t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on>&>::type
|
||||
(max)(const number<Backend, et_on>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
template <class Backend, class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(max)(const number<Backend, et_on>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
number<Backend, et_on> t(b);
|
||||
if(a > t)
|
||||
return a;
|
||||
return BOOST_MP_MOVE(t);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class Backend>
|
||||
inline typename boost::enable_if_c < boost::multiprecision::detail::is_backend<Backend>::value, const number<Backend, et_on> >::type
|
||||
(max)(const detail::expression<tag, A1, A2, A3, A4>& a, const number<Backend, et_on>& b)
|
||||
{
|
||||
number<Backend, et_on> t(a);
|
||||
if(t > b)
|
||||
return BOOST_MP_MOVE(t);
|
||||
return b;
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4, class tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type
|
||||
(max)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 > t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
template <class tag, class A1, class A2, class A3, class A4>
|
||||
inline typename detail::expression<tag, A1, A2, A3, A4>::result_type (max)(const detail::expression<tag, A1, A2, A3, A4>& a, const detail::expression<tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typename detail::expression<tag, A1, A2, A3, A4>::result_type t1(a), t2(b);
|
||||
if(t1 > t2)
|
||||
return BOOST_MP_MOVE(t1);
|
||||
return BOOST_MP_MOVE(t2);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,624 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MP_NO_ET_OPS_HPP
|
||||
#define BOOST_MP_NO_ET_OPS_HPP
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4714)
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
|
||||
//
|
||||
// Operators for non-expression template enabled number.
|
||||
// NOTE: this is not a complete header - really just a suffix to default_ops.hpp.
|
||||
// NOTE: these operators have to be defined after the methods in default_ops.hpp.
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (const number<B, et_off>& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(is_signed_number<B>::value, "Negating an unsigned type results in ill-defined behavior.");
|
||||
number<B, et_off> result(v);
|
||||
result.backend().negate();
|
||||
return result;
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator ~ (const number<B, et_off>& v)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
eval_complement(result.backend(), v.backend());
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Addition:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_add;
|
||||
eval_add(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Subtraction:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator - (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator - (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Multiply:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// divide:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator / (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator / (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator / (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// modulus:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator % (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator % (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator % (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(result.backend(), number<B, et_off>::canonical_value(a), b.backend());
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Bitwise or:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Bitwise xor:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Bitwise and:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (const number<B, et_off>& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(result.backend(), a.backend(), b.backend());
|
||||
return result;
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (const number<B, et_off>& a, const V& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(result.backend(), a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return result;
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (const V& a, const number<B, et_off>& b)
|
||||
{
|
||||
number<B, et_off> result;
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(result.backend(), b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// shifts:
|
||||
//
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator << (const number<B, et_off>& a, const I& b)
|
||||
{
|
||||
number<B, et_off> result(a);
|
||||
using default_ops::eval_left_shift;
|
||||
detail::check_shift_range(b, mpl::bool_<(sizeof(I) > sizeof(std::size_t))>(), is_signed<I>());
|
||||
eval_left_shift(result.backend(), b);
|
||||
return result;
|
||||
}
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator >> (const number<B, et_off>& a, const I& b)
|
||||
{
|
||||
number<B, et_off> result(a);
|
||||
using default_ops::eval_right_shift;
|
||||
detail::check_shift_range(b, mpl::bool_<(sizeof(I) > sizeof(std::size_t))>(), is_signed<I>());
|
||||
eval_right_shift(result.backend(), b);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !(defined(__GNUC__) && ((__GNUC__ == 4) && (__GNUC_MINOR__ < 5)))
|
||||
//
|
||||
// If we have rvalue references go all over again with rvalue ref overloads and move semantics.
|
||||
// Note that while it would be tempting to implement these so they return an rvalue reference
|
||||
// (and indeed this would be optimally efficient), this is unsafe due to users propensity to
|
||||
// write:
|
||||
//
|
||||
// const T& t = a * b;
|
||||
//
|
||||
// which would lead to a dangling reference if we didn't return by value. Of course move
|
||||
// semantics help a great deal in return by value, so performance is still pretty good...
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (number<B, et_off>&& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(is_signed_number<B>::value, "Negating an unsigned type results in ill-defined behavior.");
|
||||
v.backend().negate();
|
||||
return static_cast<number<B, et_off>&&>(v);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ~ (number<B, et_off>&& v)
|
||||
{
|
||||
eval_complement(v.backend(), v.backend());
|
||||
return static_cast<number<B, et_off>&&>(v);
|
||||
}
|
||||
//
|
||||
// Addition:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator + (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator + (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
eval_add(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Subtraction:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_signed_number<B>, number<B, et_off> >::type operator - (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(b.backend(), a.backend());
|
||||
b.backend().negate();
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator - (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator - (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<(is_compatible_arithmetic_type<V, number<B, et_off> >::value && is_signed_number<B>::value), number<B, et_off> >::type
|
||||
operator - (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_subtract;
|
||||
eval_subtract(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
b.backend().negate();
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Multiply:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator * (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator * (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_multiply;
|
||||
eval_multiply(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// divide:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE number<B, et_off> operator / (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if<is_compatible_arithmetic_type<V, number<B, et_off> >, number<B, et_off> >::type
|
||||
operator / (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_divide;
|
||||
eval_divide(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
//
|
||||
// modulus:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator % (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator % (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_modulus;
|
||||
eval_modulus(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
//
|
||||
// Bitwise or:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator | (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator | (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_or;
|
||||
eval_bitwise_or(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Bitwise xor:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator ^ (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator ^ (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_xor;
|
||||
eval_bitwise_xor(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// Bitwise and:
|
||||
//
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (number<B, et_off>&& a, const number<B, et_off>& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (const number<B, et_off>& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(b.backend(), a.backend());
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
template <class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<number_category<B>::value == number_kind_integer, number<B, et_off> >::type operator & (number<B, et_off>&& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(a.backend(), b.backend());
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class V>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (number<B, et_off>&& a, const V& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(a.backend(), number<B, et_off>::canonical_value(b));
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class V, class B>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_compatible_arithmetic_type<V, number<B, et_off> >::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator & (const V& a, number<B, et_off>&& b)
|
||||
{
|
||||
using default_ops::eval_bitwise_and;
|
||||
eval_bitwise_and(b.backend(), number<B, et_off>::canonical_value(a));
|
||||
return static_cast<number<B, et_off>&&>(b);
|
||||
}
|
||||
//
|
||||
// shifts:
|
||||
//
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator << (number<B, et_off>&& a, const I& b)
|
||||
{
|
||||
using default_ops::eval_left_shift;
|
||||
eval_left_shift(a.backend(), b);
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
template <class B, class I>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_integral<I>::value && (number_category<B>::value == number_kind_integer), number<B, et_off> >::type
|
||||
operator >> (number<B, et_off>&& a, const I& b)
|
||||
{
|
||||
using default_ops::eval_right_shift;
|
||||
eval_right_shift(a.backend(), b);
|
||||
return static_cast<number<B, et_off>&&>(a);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MP_NO_ET_OPS_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,664 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MP_COMPARE_HPP
|
||||
#define BOOST_MP_COMPARE_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/is_backend.hpp>
|
||||
|
||||
//
|
||||
// Comparison operators for number.
|
||||
//
|
||||
|
||||
namespace boost{ namespace multiprecision{
|
||||
|
||||
namespace default_ops{
|
||||
|
||||
//
|
||||
// The dispatching mechanism used here to deal with differently typed arguments
|
||||
// could be better replaced with enable_if overloads, but that breaks MSVC-12
|
||||
// under strange and hard to reproduce circumstances.
|
||||
//
|
||||
template <class B>
|
||||
inline bool eval_eq(const B& a, const B& b)
|
||||
{
|
||||
return a.compare(b) == 0;
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_eq_imp(const T& a, const U& b, const mpl::true_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
|
||||
return eval_eq(a, t.backend());
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_eq_imp(const T& a, const U& b, const mpl::false_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
|
||||
return eval_eq(t.backend(), b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_eq(const T& a, const U& b)
|
||||
{
|
||||
typedef mpl::bool_<boost::multiprecision::detail::is_first_backend<T, U>::value> tag_type;
|
||||
return eval_eq_imp(a, b, tag_type());
|
||||
}
|
||||
|
||||
template <class B>
|
||||
inline bool eval_lt(const B& a, const B& b)
|
||||
{
|
||||
return a.compare(b) < 0;
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_lt_imp(const T& a, const U& b, const mpl::true_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
|
||||
return eval_lt(a, t.backend());
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_lt_imp(const T& a, const U& b, const mpl::false_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
|
||||
return eval_lt(t.backend(), b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_lt(const T& a, const U& b)
|
||||
{
|
||||
typedef mpl::bool_<boost::multiprecision::detail::is_first_backend<T, U>::value> tag_type;
|
||||
return eval_lt_imp(a, b, tag_type());
|
||||
}
|
||||
|
||||
template <class B>
|
||||
inline bool eval_gt(const B& a, const B& b)
|
||||
{
|
||||
return a.compare(b) > 0;
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_gt_imp(const T& a, const U& b, const mpl::true_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b);
|
||||
return eval_gt(a, t.backend());
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_gt_imp(const T& a, const U& b, const mpl::false_&)
|
||||
{
|
||||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a);
|
||||
return eval_gt(t.backend(), b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline bool eval_gt(const T& a, const U& b)
|
||||
{
|
||||
typedef mpl::bool_<boost::multiprecision::detail::is_first_backend<T, U>::value> tag_type;
|
||||
return eval_gt_imp(a, b, tag_type());
|
||||
}
|
||||
|
||||
} // namespace default_ops
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class Num, class Val>
|
||||
struct is_valid_mixed_compare : public mpl::false_ {};
|
||||
|
||||
template <class B, expression_template_option ET, class Val>
|
||||
struct is_valid_mixed_compare<number<B, ET>, Val> : public is_convertible<Val, number<B, ET> > {};
|
||||
|
||||
template <class B, expression_template_option ET>
|
||||
struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {};
|
||||
|
||||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
|
||||
struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
|
||||
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
inline
|
||||
#if !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40700)
|
||||
BOOST_CONSTEXPR
|
||||
#endif
|
||||
typename boost::enable_if_c<number_category<Backend>::value == number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>& a)
|
||||
{
|
||||
using default_ops::eval_fpclassify;
|
||||
return eval_fpclassify(a.backend()) == FP_NAN;
|
||||
}
|
||||
|
||||
template <class Arithmetic>
|
||||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
template <class Arithmetic>
|
||||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a)
|
||||
{
|
||||
return (boost::math::isnan)(a);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b)
|
||||
{
|
||||
return is_unordered_value(a) || is_unordered_value(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator == (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_eq(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return eval_eq(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return eval_eq(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return eval_eq(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool operator != (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return true;
|
||||
return !eval_eq(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return true;
|
||||
return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
if(detail::is_unordered_comparison(a, b)) return true;
|
||||
return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return true;
|
||||
return !eval_eq(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_eq;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return true;
|
||||
return !eval_eq(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_eq;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return true;
|
||||
return !eval_eq(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline typename boost::enable_if_c<(number_category<Backend>::value != number_kind_complex) && (number_category<Backend2>::value != number_kind_complex), bool>::type
|
||||
operator < (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_lt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return eval_gt(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return eval_lt(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if_c<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return eval_lt(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline typename boost::enable_if_c<(number_category<Backend>::value != number_kind_complex) && (number_category<Backend2>::value != number_kind_complex), bool>::type
|
||||
operator > (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_gt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return a > t;
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return t > b;
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if_c<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return t > t2;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline typename boost::enable_if_c<(number_category<Backend>::value != number_kind_complex) && (number_category<Backend2>::value != number_kind_complex), bool>::type
|
||||
operator <= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_gt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_value(a) || detail::is_unordered_value(b))
|
||||
return false;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return !eval_lt(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return !eval_gt(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if_c<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return !eval_gt(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline typename boost::enable_if_c<(number_category<Backend>::value != number_kind_complex) && (number_category<Backend2>::value != number_kind_complex), bool>::type
|
||||
operator >= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_lt(a.backend(), b.backend());
|
||||
}
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
|
||||
}
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value && (number_category<Backend>::value != number_kind_complex), bool>::type
|
||||
operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
using default_ops::eval_gt;
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
|
||||
}
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_gt;
|
||||
result_type t(b);
|
||||
if(detail::is_unordered_comparison(a, t)) return false;
|
||||
return !eval_gt(t.backend(), result_type::canonical_value(a));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
|
||||
{
|
||||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
|
||||
using default_ops::eval_lt;
|
||||
result_type t(a);
|
||||
if(detail::is_unordered_comparison(t, b)) return false;
|
||||
return !eval_lt(t.backend(), result_type::canonical_value(b));
|
||||
}
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if_c<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>::value && (number_category<typename detail::expression<Tag, A1, A2, A3, A4>::result_type>::value != number_kind_complex), bool>::type
|
||||
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
|
||||
{
|
||||
using default_ops::eval_lt;
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b);
|
||||
if(detail::is_unordered_comparison(t, t2)) return false;
|
||||
return !eval_lt(t.backend(), t2.backend());
|
||||
}
|
||||
|
||||
//
|
||||
// C99 comparison macros as functions:
|
||||
//
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a > b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a > b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a > b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a > b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a > b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a > b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a >= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a >= b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a >= b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a >= b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a >= b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a >= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a <= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a <= b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a <= b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a <= b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a <= b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
islessequal BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a <= b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isless BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return a < b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return a < b; }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return a < b; }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { return a < b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { return a < b; }
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isless BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { return a < b; }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b)
|
||||
{
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return a != b;
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
|
||||
{
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return a != b;
|
||||
}
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
if(detail::is_unordered_comparison(a, b)) return false;
|
||||
return a != b;
|
||||
}
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type b(bb);
|
||||
return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(a, b);
|
||||
}
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const Arithmetic& b)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(a, b);
|
||||
}
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type b(bb);
|
||||
return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION(a, b);
|
||||
}
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
inline bool isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) { return detail::is_unordered_comparison(a, b); }
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { return detail::is_unordered_comparison(a, b); }
|
||||
|
||||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { return detail::is_unordered_comparison(a, b); }
|
||||
|
||||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type b(bb);
|
||||
return detail::is_unordered_comparison(a, b);
|
||||
}
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
|
||||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const Arithmetic& b)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
return detail::is_unordered_comparison(a, b);
|
||||
}
|
||||
|
||||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
|
||||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
|
||||
isunordered BOOST_PREVENT_MACRO_SUBSTITUTION(const detail::expression<Tag, A1, A2, A3, A4>& aa, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& bb)
|
||||
{
|
||||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type a(aa);
|
||||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type b(bb);
|
||||
return detail::is_unordered_comparison(a, b);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MP_COMPARE_HPP
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock.
|
||||
// Copyright Christopher Kormanyos 2013. 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_MP_DETAIL_REBIND_HPP
|
||||
#define BOOST_MP_DETAIL_REBIND_HPP
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace detail
|
||||
{
|
||||
template <class value_type, class my_allocator>
|
||||
struct rebind
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_ALLOCATOR
|
||||
typedef typename std::allocator_traits<my_allocator>::template rebind_alloc<value_type> type;
|
||||
#else
|
||||
typedef typename my_allocator::template rebind<value_type>::other type;
|
||||
#endif
|
||||
};
|
||||
} } } } // namespace boost::multiprecision::backends::detail
|
||||
|
||||
#endif // BOOST_MP_DETAIL_REBIND_HPP
|
||||
@@ -0,0 +1,77 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MP_UBLAS_HPP
|
||||
#define BOOST_MP_UBLAS_HPP
|
||||
|
||||
namespace boost { namespace numeric { namespace ublas {
|
||||
|
||||
template<class V>
|
||||
class sparse_vector_element;
|
||||
|
||||
template <class V, class Backend, multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline bool operator == (const sparse_vector_element<V>& a, const ::boost::multiprecision::number<Backend, ExpressionTemplates>& b)
|
||||
{
|
||||
typedef typename sparse_vector_element<V>::const_reference ref_type;
|
||||
return static_cast<ref_type>(a) == b;
|
||||
}
|
||||
|
||||
template<class X, class Y>
|
||||
struct promote_traits;
|
||||
|
||||
template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class Backend2, boost::multiprecision::expression_template_option ExpressionTemplates2>
|
||||
struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> number1_t;
|
||||
typedef boost::multiprecision::number<Backend2, ExpressionTemplates2> number2_t;
|
||||
typedef typename mpl::if_c<
|
||||
is_convertible<number1_t, number2_t>::value && !is_convertible<number2_t, number1_t>::value,
|
||||
number2_t, number1_t
|
||||
>::type promote_type;
|
||||
};
|
||||
|
||||
template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class Arithmetic>
|
||||
struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, Arithmetic>
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> promote_type;
|
||||
};
|
||||
|
||||
template <class Arithmetic, class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1>
|
||||
struct promote_traits<Arithmetic, boost::multiprecision::number<Backend1, ExpressionTemplates1> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> promote_type;
|
||||
};
|
||||
|
||||
template <class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct promote_traits<boost::multiprecision::number<Backend1, ExpressionTemplates1>, boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> number1_t;
|
||||
typedef boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> expression_type;
|
||||
typedef typename expression_type::result_type number2_t;
|
||||
typedef typename promote_traits<number1_t, number2_t>::promote_type promote_type;
|
||||
};
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Backend1, boost::multiprecision::expression_template_option ExpressionTemplates1>
|
||||
struct promote_traits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::number<Backend1, ExpressionTemplates1> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend1, ExpressionTemplates1> number1_t;
|
||||
typedef boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> expression_type;
|
||||
typedef typename expression_type::result_type number2_t;
|
||||
typedef typename promote_traits<number1_t, number2_t>::promote_type promote_type;
|
||||
};
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class tagb, class Arg1b, class Arg2b, class Arg3b, class Arg4b>
|
||||
struct promote_traits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::detail::expression<tagb, Arg1b, Arg2b, Arg3b, Arg4b> >
|
||||
{
|
||||
typedef boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> expression1_t;
|
||||
typedef typename expression1_t::result_type number1_t;
|
||||
typedef boost::multiprecision::detail::expression<tagb, Arg1b, Arg2b, Arg3b, Arg4b> expression2_t;
|
||||
typedef typename expression2_t::result_type number2_t;
|
||||
};
|
||||
|
||||
}}} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock.
|
||||
// Copyright Christopher Kormanyos 2013. 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_MP_UTYPE_HELPER_HPP
|
||||
#define BOOST_MP_UTYPE_HELPER_HPP
|
||||
|
||||
#include <limits>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost { namespace multiprecision {
|
||||
namespace detail
|
||||
{
|
||||
template<const unsigned> struct utype_helper { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<0U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<1U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<2U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<3U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<4U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<5U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<6U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<7U> { typedef boost::uint8_t exact; };
|
||||
template<> struct utype_helper<8U> { typedef boost::uint8_t exact; };
|
||||
|
||||
template<> struct utype_helper<9U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<10U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<11U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<12U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<13U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<14U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<15U> { typedef boost::uint16_t exact; };
|
||||
template<> struct utype_helper<16U> { typedef boost::uint16_t exact; };
|
||||
|
||||
template<> struct utype_helper<17U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<18U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<19U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<20U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<21U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<22U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<23U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<24U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<25U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<26U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<27U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<28U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<29U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<30U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<31U> { typedef boost::uint32_t exact; };
|
||||
template<> struct utype_helper<32U> { typedef boost::uint32_t exact; };
|
||||
|
||||
template<> struct utype_helper<33U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<34U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<35U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<36U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<37U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<38U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<39U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<40U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<41U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<42U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<43U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<44U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<45U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<46U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<47U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<48U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<49U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<50U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<51U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<52U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<53U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<54U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<55U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<56U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<57U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<58U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<59U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<60U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<61U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<62U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<63U> { typedef boost::uint64_t exact; };
|
||||
template<> struct utype_helper<64U> { typedef boost::uint64_t exact; };
|
||||
|
||||
template<class unsigned_type>
|
||||
int utype_prior(unsigned_type ui)
|
||||
{
|
||||
// TBD: Implement a templated binary search for this.
|
||||
int priority_bit;
|
||||
|
||||
unsigned_type priority_mask = unsigned_type(unsigned_type(1U) << (std::numeric_limits<unsigned_type>::digits - 1));
|
||||
|
||||
for(priority_bit = std::numeric_limits<unsigned_type>::digits - 1; priority_bit >= 0; --priority_bit)
|
||||
{
|
||||
if(unsigned_type(priority_mask & ui) != unsigned_type(0U))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
priority_mask >>= 1;
|
||||
}
|
||||
|
||||
return priority_bit;
|
||||
}
|
||||
|
||||
} } }
|
||||
|
||||
#endif // BOOST_MP_UTYPE_HELPER_HPP
|
||||
@@ -0,0 +1,173 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2018 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_MP_EIGEN_HPP
|
||||
#define BOOST_MP_EIGEN_HPP
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
#include <Eigen/Core>
|
||||
|
||||
//
|
||||
// Generic Eigen support code:
|
||||
//
|
||||
namespace Eigen
|
||||
{
|
||||
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend, ExpressionTemplates> self_type;
|
||||
typedef typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type Real;
|
||||
typedef self_type NonInteger; // Not correct but we can't do much better??
|
||||
typedef double Literal;
|
||||
typedef self_type Nested;
|
||||
enum {
|
||||
IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
|
||||
IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
|
||||
ReadCost = 1,
|
||||
AddCost = 4,
|
||||
MulCost = 8,
|
||||
IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
|
||||
RequireInitialization = 1,
|
||||
};
|
||||
static Real epsilon()
|
||||
{
|
||||
return std::numeric_limits<Real>::epsilon();
|
||||
}
|
||||
static Real dummy_precision()
|
||||
{
|
||||
return 1000 * epsilon();
|
||||
}
|
||||
static Real highest()
|
||||
{
|
||||
return (std::numeric_limits<Real>::max)();
|
||||
}
|
||||
static Real lowest()
|
||||
{
|
||||
return (std::numeric_limits<Real>::min)();
|
||||
}
|
||||
static int digits10_imp(const boost::mpl::true_&)
|
||||
{
|
||||
return std::numeric_limits<Real>::digits10;
|
||||
}
|
||||
template <bool B>
|
||||
static int digits10_imp(const boost::mpl::bool_<B>&)
|
||||
{
|
||||
return Real::default_precision();
|
||||
}
|
||||
static int digits10()
|
||||
{
|
||||
return digits10_imp(boost::mpl::bool_<std::numeric_limits<Real>::digits10 && (std::numeric_limits<Real>::digits10 != INT_MAX) ? true : false>());
|
||||
}
|
||||
};
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct NumTraits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > : public NumTraits<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>
|
||||
{
|
||||
};
|
||||
|
||||
#define BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(A)\
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp>\
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, A, BinaryOp>\
|
||||
{\
|
||||
/*static_assert(boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");*/\
|
||||
typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;\
|
||||
};\
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp>\
|
||||
struct ScalarBinaryOpTraits<A, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp>\
|
||||
{\
|
||||
/*static_assert(boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");*/\
|
||||
typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;\
|
||||
};\
|
||||
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(float)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(double)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(long double)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(char)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned char)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(signed char)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(short)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned short)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(int)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned int)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(long)
|
||||
BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned long)
|
||||
|
||||
#if 0
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Backend2, boost::multiprecision::expression_template_option ExpressionTemplates2, typename BinaryOp>
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2>, BinaryOp>
|
||||
{
|
||||
static_assert(
|
||||
boost::multiprecision::is_compatible_arithmetic_type<boost::multiprecision::number<Backend2, ExpressionTemplates2>, boost::multiprecision::number<Backend, ExpressionTemplates> >::value
|
||||
|| boost::multiprecision::is_compatible_arithmetic_type<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >::value, "Interoperability with this arithmetic type is not supported.");
|
||||
typedef typename boost::mpl::if_c<boost::is_convertible<boost::multiprecision::number<Backend2, ExpressionTemplates2>, boost::multiprecision::number<Backend, ExpressionTemplates> >::value,
|
||||
boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >::type ReturnType;
|
||||
};
|
||||
|
||||
template<unsigned D, typename BinaryOp>
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<D>, boost::multiprecision::et_on>, boost::multiprecision::mpfr_float, BinaryOp>
|
||||
{
|
||||
typedef boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<D>, boost::multiprecision::et_on> ReturnType;
|
||||
};
|
||||
|
||||
template<typename BinaryOp>
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::mpfr_float, boost::multiprecision::mpc_complex, BinaryOp>
|
||||
{
|
||||
typedef boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>, boost::multiprecision::et_on> ReturnType;
|
||||
};
|
||||
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp>
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp>
|
||||
{
|
||||
typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4, typename BinaryOp>
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, BinaryOp>
|
||||
{
|
||||
static_assert(boost::is_convertible<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");
|
||||
typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;
|
||||
};
|
||||
|
||||
template<class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp>
|
||||
struct ScalarBinaryOpTraits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp>
|
||||
{
|
||||
static_assert(boost::is_convertible<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");
|
||||
typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;
|
||||
};
|
||||
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template<typename Scalar>
|
||||
struct conj_retval;
|
||||
|
||||
template<typename Scalar, bool IsComplex>
|
||||
struct conj_impl;
|
||||
|
||||
|
||||
template<class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct conj_retval<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> >
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type type;
|
||||
};
|
||||
|
||||
template<class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
struct conj_impl<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, true>
|
||||
{
|
||||
EIGEN_DEVICE_FUNC
|
||||
static inline typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type run(const typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& x)
|
||||
{
|
||||
return conj(x);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,737 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_FLOAT128_HPP
|
||||
#define BOOST_MP_FLOAT128_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
|
||||
#if defined(BOOST_INTEL) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD)
|
||||
# if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION >= 1310) && defined(__GNUC__)
|
||||
# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
|
||||
# define BOOST_MP_USE_FLOAT128
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef BOOST_MP_USE_FLOAT128
|
||||
# define BOOST_MP_USE_QUAD
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD)
|
||||
# define BOOST_MP_USE_FLOAT128
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD)
|
||||
# error "Sorry compiler is neither GCC, not Intel, don't know how to configure this header."
|
||||
#endif
|
||||
#if defined(BOOST_MP_USE_FLOAT128) && defined(BOOST_MP_USE_QUAD)
|
||||
# error "Oh dear, both BOOST_MP_USE_FLOAT128 and BOOST_MP_USE_QUAD are defined, which one should I be using?"
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MP_USE_FLOAT128)
|
||||
|
||||
extern "C" {
|
||||
#include <quadmath.h>
|
||||
}
|
||||
|
||||
typedef __float128 float128_type;
|
||||
|
||||
#elif defined(BOOST_MP_USE_QUAD)
|
||||
|
||||
#include <boost/multiprecision/detail/float_string_cvt.hpp>
|
||||
|
||||
typedef _Quad float128_type;
|
||||
|
||||
extern "C" {
|
||||
_Quad __ldexpq(_Quad, int);
|
||||
_Quad __frexpq(_Quad, int*);
|
||||
_Quad __fabsq(_Quad);
|
||||
_Quad __floorq(_Quad);
|
||||
_Quad __ceilq(_Quad);
|
||||
_Quad __sqrtq(_Quad);
|
||||
_Quad __truncq(_Quad);
|
||||
_Quad __expq(_Quad);
|
||||
_Quad __powq(_Quad, _Quad);
|
||||
_Quad __logq(_Quad);
|
||||
_Quad __log10q(_Quad);
|
||||
_Quad __sinq(_Quad);
|
||||
_Quad __cosq(_Quad);
|
||||
_Quad __tanq(_Quad);
|
||||
_Quad __asinq(_Quad);
|
||||
_Quad __acosq(_Quad);
|
||||
_Quad __atanq(_Quad);
|
||||
_Quad __sinhq(_Quad);
|
||||
_Quad __coshq(_Quad);
|
||||
_Quad __tanhq(_Quad);
|
||||
_Quad __fmodq(_Quad, _Quad);
|
||||
_Quad __atan2q(_Quad, _Quad);
|
||||
|
||||
#define ldexpq __ldexpq
|
||||
#define frexpq __frexpq
|
||||
#define fabsq __fabsq
|
||||
#define floorq __floorq
|
||||
#define ceilq __ceilq
|
||||
#define sqrtq __sqrtq
|
||||
#define truncq __truncq
|
||||
#define expq __expq
|
||||
#define powq __powq
|
||||
#define logq __logq
|
||||
#define log10q __log10q
|
||||
#define sinq __sinq
|
||||
#define cosq __cosq
|
||||
#define tanq __tanq
|
||||
#define asinq __asinq
|
||||
#define acosq __acosq
|
||||
#define atanq __atanq
|
||||
#define sinhq __sinhq
|
||||
#define coshq __coshq
|
||||
#define tanhq __tanhq
|
||||
#define fmodq __fmodq
|
||||
#define atan2q __atan2q
|
||||
}
|
||||
|
||||
inline _Quad isnanq(_Quad v)
|
||||
{
|
||||
return v != v;
|
||||
}
|
||||
inline _Quad isinfq(_Quad v)
|
||||
{
|
||||
return __fabsq(v) > 1.18973149535723176508575932662800702e4932Q;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace backends{
|
||||
|
||||
struct float128_backend;
|
||||
|
||||
}
|
||||
|
||||
using backends::float128_backend;
|
||||
|
||||
template<>
|
||||
struct number_category<backends::float128_backend> : public mpl::int_<number_kind_floating_point> {};
|
||||
#if defined(BOOST_MP_USE_QUAD)
|
||||
template<>
|
||||
struct number_category<float128_type> : public mpl::int_<number_kind_floating_point> {};
|
||||
#endif
|
||||
|
||||
typedef number<float128_backend, et_off> float128;
|
||||
|
||||
namespace backends{
|
||||
|
||||
struct float128_backend
|
||||
{
|
||||
typedef mpl::list<signed char, short, int, long, boost::long_long_type> signed_types;
|
||||
typedef mpl::list<unsigned char, unsigned short,
|
||||
unsigned int, unsigned long, boost::ulong_long_type> unsigned_types;
|
||||
typedef mpl::list<float, double, long double> float_types;
|
||||
typedef int exponent_type;
|
||||
|
||||
private:
|
||||
float128_type m_value;
|
||||
public:
|
||||
BOOST_CONSTEXPR float128_backend() BOOST_NOEXCEPT : m_value(0) {}
|
||||
BOOST_CONSTEXPR float128_backend(const float128_backend& o) BOOST_NOEXCEPT : m_value(o.m_value) {}
|
||||
float128_backend& operator = (const float128_backend& o) BOOST_NOEXCEPT
|
||||
{
|
||||
m_value = o.m_value;
|
||||
return *this;
|
||||
}
|
||||
template <class T>
|
||||
BOOST_CONSTEXPR float128_backend(const T& i, const typename enable_if_c<is_convertible<T, float128_type>::value>::type* = 0) BOOST_NOEXCEPT_IF(noexcept(std::declval<float128_type&>() = std::declval<const T&>()))
|
||||
: m_value(i) {}
|
||||
template <class T>
|
||||
typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, float128_type>::value, float128_backend&>::type operator = (const T& i) BOOST_NOEXCEPT_IF(noexcept(std::declval<float128_type&>() = std::declval<const T&>()))
|
||||
{
|
||||
m_value = i;
|
||||
return *this;
|
||||
}
|
||||
float128_backend(long double const& f)
|
||||
{
|
||||
if(boost::math::isinf(f))
|
||||
m_value = (f < 0) ? -1.0Q / 0.0Q : 1.0Q / 0.0Q;
|
||||
else
|
||||
m_value = f;
|
||||
}
|
||||
float128_backend& operator=(long double const& f)
|
||||
{
|
||||
if(boost::math::isinf(f))
|
||||
m_value = (f < 0) ? -1.0Q / 0.0Q : 1.0Q / 0.0Q;
|
||||
else
|
||||
m_value = f;
|
||||
return *this;
|
||||
}
|
||||
float128_backend& operator = (const char* s)
|
||||
{
|
||||
#ifndef BOOST_MP_USE_QUAD
|
||||
char* p_end;
|
||||
m_value = strtoflt128(s, &p_end);
|
||||
if(p_end - s != (std::ptrdiff_t)std::strlen(s))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a floating point value"));
|
||||
}
|
||||
#else
|
||||
boost::multiprecision::detail::convert_from_string(*this, s);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void swap(float128_backend& o) BOOST_NOEXCEPT
|
||||
{
|
||||
std::swap(m_value, o.value());
|
||||
}
|
||||
std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
|
||||
{
|
||||
#ifndef BOOST_MP_USE_QUAD
|
||||
char buf[100];
|
||||
boost::scoped_array<char> buf2;
|
||||
std::string format = "%";
|
||||
if(f & std::ios_base::showpos)
|
||||
format += "+";
|
||||
if(f & std::ios_base::showpoint)
|
||||
format += "#";
|
||||
format += ".*";
|
||||
if(digits == 0)
|
||||
digits = 36;
|
||||
format += "Q";
|
||||
if(f & std::ios_base::scientific)
|
||||
format += "e";
|
||||
else if(f & std::ios_base::fixed)
|
||||
format += "f";
|
||||
else
|
||||
format += "g";
|
||||
|
||||
int v = quadmath_snprintf (buf, 100, format.c_str(), digits, m_value);
|
||||
|
||||
if((v < 0) || (v >= 99))
|
||||
{
|
||||
int v_max = v;
|
||||
buf2.reset(new char[v+3]);
|
||||
v = quadmath_snprintf (&buf2[0], v_max + 3, format.c_str(), digits, m_value);
|
||||
if(v >= v_max + 3)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of float128_type failed."));
|
||||
}
|
||||
return &buf2[0];
|
||||
}
|
||||
return buf;
|
||||
#else
|
||||
return boost::multiprecision::detail::convert_to_string(*this, digits ? digits : 37, f);
|
||||
#endif
|
||||
}
|
||||
void negate() BOOST_NOEXCEPT
|
||||
{
|
||||
m_value = -m_value;
|
||||
}
|
||||
int compare(const float128_backend& o)const
|
||||
{
|
||||
return m_value == o.m_value ? 0 : m_value < o.m_value ? -1 : 1;
|
||||
}
|
||||
template <class T>
|
||||
int compare(const T& i)const
|
||||
{
|
||||
return m_value == i ? 0 : m_value < i ? -1 : 1;
|
||||
}
|
||||
float128_type& value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
const float128_type& value()const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
};
|
||||
|
||||
inline void eval_add(float128_backend& result, const float128_backend& a)
|
||||
{
|
||||
result.value() += a.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_add(float128_backend& result, const A& a)
|
||||
{
|
||||
result.value() += a;
|
||||
}
|
||||
inline void eval_subtract(float128_backend& result, const float128_backend& a)
|
||||
{
|
||||
result.value() -= a.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_subtract(float128_backend& result, const A& a)
|
||||
{
|
||||
result.value() -= a;
|
||||
}
|
||||
inline void eval_multiply(float128_backend& result, const float128_backend& a)
|
||||
{
|
||||
result.value() *= a.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_multiply(float128_backend& result, const A& a)
|
||||
{
|
||||
result.value() *= a;
|
||||
}
|
||||
inline void eval_divide(float128_backend& result, const float128_backend& a)
|
||||
{
|
||||
result.value() /= a.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_divide(float128_backend& result, const A& a)
|
||||
{
|
||||
result.value() /= a;
|
||||
}
|
||||
|
||||
inline void eval_add(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = a.value() + b.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_add(float128_backend& result, const float128_backend& a, const A& b)
|
||||
{
|
||||
result.value() = a.value() + b;
|
||||
}
|
||||
inline void eval_subtract(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = a.value() - b.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_subtract(float128_backend& result, const float128_backend& a, const A& b)
|
||||
{
|
||||
result.value() = a.value() - b;
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_subtract(float128_backend& result, const A& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = a - b.value();
|
||||
}
|
||||
inline void eval_multiply(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = a.value() * b.value();
|
||||
}
|
||||
template <class A>
|
||||
inline void eval_multiply(float128_backend& result, const float128_backend& a, const A& b)
|
||||
{
|
||||
result.value() = a.value() * b;
|
||||
}
|
||||
inline void eval_divide(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = a.value() / b.value();
|
||||
}
|
||||
|
||||
template <class R>
|
||||
inline void eval_convert_to(R* result, const float128_backend& val)
|
||||
{
|
||||
*result = static_cast<R>(val.value());
|
||||
}
|
||||
|
||||
inline void eval_frexp(float128_backend& result, const float128_backend& arg, int* exp)
|
||||
{
|
||||
result.value() = frexpq(arg.value(), exp);
|
||||
}
|
||||
|
||||
inline void eval_ldexp(float128_backend& result, const float128_backend& arg, int exp)
|
||||
{
|
||||
result.value() = ldexpq(arg.value(), exp);
|
||||
}
|
||||
|
||||
inline void eval_floor(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = floorq(arg.value());
|
||||
}
|
||||
inline void eval_ceil(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = ceilq(arg.value());
|
||||
}
|
||||
inline void eval_sqrt(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = sqrtq(arg.value());
|
||||
}
|
||||
inline int eval_fpclassify(const float128_backend& arg)
|
||||
{
|
||||
if(isnanq(arg.value()))
|
||||
return FP_NAN;
|
||||
else if(isinfq(arg.value()))
|
||||
return FP_INFINITE;
|
||||
else if(arg.value() == 0)
|
||||
return FP_ZERO;
|
||||
|
||||
float128_backend t(arg);
|
||||
if(t.value() < 0)
|
||||
t.negate();
|
||||
if(t.value() < 3.36210314311209350626267781732175260e-4932Q)
|
||||
return FP_SUBNORMAL;
|
||||
return FP_NORMAL;
|
||||
}
|
||||
|
||||
inline void eval_increment(float128_backend& arg)
|
||||
{
|
||||
++arg.value();
|
||||
}
|
||||
inline void eval_decrement(float128_backend& arg)
|
||||
{
|
||||
--arg.value();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* abs/fabs:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
inline void eval_abs(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = fabsq(arg.value());
|
||||
}
|
||||
inline void eval_fabs(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = fabsq(arg.value());
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Floating point functions:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
inline void eval_trunc(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = truncq(arg.value());
|
||||
}
|
||||
/*
|
||||
//
|
||||
// This doesn't actually work... rely on our own default version instead.
|
||||
//
|
||||
inline void eval_round(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
if(isnanq(arg.value()) || isinf(arg.value()))
|
||||
{
|
||||
result = boost::math::policies::raise_rounding_error(
|
||||
"boost::multiprecision::trunc<%1%>(%1%)", 0,
|
||||
number<float128_backend, et_off>(arg),
|
||||
number<float128_backend, et_off>(arg),
|
||||
boost::math::policies::policy<>()).backend();
|
||||
return;
|
||||
}
|
||||
result.value() = roundq(arg.value());
|
||||
}
|
||||
*/
|
||||
|
||||
inline void eval_exp(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = expq(arg.value());
|
||||
}
|
||||
inline void eval_log(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = logq(arg.value());
|
||||
}
|
||||
inline void eval_log10(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = log10q(arg.value());
|
||||
}
|
||||
inline void eval_sin(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = sinq(arg.value());
|
||||
}
|
||||
inline void eval_cos(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = cosq(arg.value());
|
||||
}
|
||||
inline void eval_tan(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = tanq(arg.value());
|
||||
}
|
||||
inline void eval_asin(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = asinq(arg.value());
|
||||
}
|
||||
inline void eval_acos(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = acosq(arg.value());
|
||||
}
|
||||
inline void eval_atan(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = atanq(arg.value());
|
||||
}
|
||||
inline void eval_sinh(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = sinhq(arg.value());
|
||||
}
|
||||
inline void eval_cosh(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = coshq(arg.value());
|
||||
}
|
||||
inline void eval_tanh(float128_backend& result, const float128_backend& arg)
|
||||
{
|
||||
result.value() = tanhq(arg.value());
|
||||
}
|
||||
inline void eval_fmod(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = fmodq(a.value(), b.value());
|
||||
}
|
||||
inline void eval_pow(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = powq(a.value(), b.value());
|
||||
}
|
||||
inline void eval_atan2(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = atan2q(a.value(), b.value());
|
||||
}
|
||||
#ifndef BOOST_MP_USE_QUAD
|
||||
inline void eval_multiply_add(float128_backend& result, const float128_backend& a, const float128_backend& b, const float128_backend& c)
|
||||
{
|
||||
result.value() = fmaq(a.value(), b.value(), c.value());
|
||||
}
|
||||
inline int eval_signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const float128_backend& arg)
|
||||
{
|
||||
return ::signbitq(arg.value());
|
||||
}
|
||||
#endif
|
||||
|
||||
inline std::size_t hash_value(const float128_backend& val)
|
||||
{
|
||||
return boost::hash_value(static_cast<double>(val.value()));
|
||||
}
|
||||
|
||||
} // namespace backends
|
||||
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return asinhq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return acoshq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return atanhq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return cbrtq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return erfq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return erfcq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return expm1q(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return lgammaq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return tgammaq(arg.backend().value());
|
||||
}
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<float128_backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
|
||||
{
|
||||
return log1pq(arg.backend().value());
|
||||
}
|
||||
|
||||
#ifndef BOOST_MP_USE_QUAD
|
||||
template <multiprecision::expression_template_option ExpressionTemplates>
|
||||
inline boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& a, const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& b)
|
||||
{
|
||||
return ::copysignq(a.backend().value(), b.backend().value());
|
||||
}
|
||||
|
||||
inline void eval_remainder(float128_backend& result, const float128_backend& a, const float128_backend& b)
|
||||
{
|
||||
result.value() = remainderq(a.value(), b.value());
|
||||
}
|
||||
inline void eval_remainder(float128_backend& result, const float128_backend& a, const float128_backend& b, int* pi)
|
||||
{
|
||||
result.value() = remquoq(a.value(), b.value(), pi);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace multiprecision
|
||||
|
||||
namespace math {
|
||||
|
||||
using boost::multiprecision::signbit;
|
||||
using boost::multiprecision::copysign;
|
||||
|
||||
} // namespace math
|
||||
|
||||
} // namespace boost
|
||||
|
||||
namespace boost{
|
||||
namespace archive{
|
||||
|
||||
class binary_oarchive;
|
||||
class binary_iarchive;
|
||||
|
||||
}
|
||||
|
||||
namespace serialization{ namespace float128_detail{
|
||||
|
||||
template <class Archive>
|
||||
void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::false_&, const mpl::false_&)
|
||||
{
|
||||
// saving
|
||||
// non-binary
|
||||
std::string s(val.str(0, std::ios_base::scientific));
|
||||
ar & s;
|
||||
}
|
||||
template <class Archive>
|
||||
void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::false_&)
|
||||
{
|
||||
// loading
|
||||
// non-binary
|
||||
std::string s;
|
||||
ar & s;
|
||||
val = s.c_str();
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::false_&, const mpl::true_&)
|
||||
{
|
||||
// saving
|
||||
// binary
|
||||
ar.save_binary(&val, sizeof(val));
|
||||
}
|
||||
template <class Archive>
|
||||
void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::true_&)
|
||||
{
|
||||
// loading
|
||||
// binary
|
||||
ar.load_binary(&val, sizeof(val));
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, unsigned int /*version*/)
|
||||
{
|
||||
typedef typename Archive::is_loading load_tag;
|
||||
typedef typename mpl::bool_<boost::is_same<Archive, boost::archive::binary_oarchive>::value || boost::is_same<Archive, boost::archive::binary_iarchive>::value> binary_tag;
|
||||
|
||||
float128_detail::do_serialize(ar, val, load_tag(), binary_tag());
|
||||
}
|
||||
|
||||
} // namepsace archive
|
||||
|
||||
} // namespace boost
|
||||
|
||||
namespace std{
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >
|
||||
{
|
||||
typedef boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> number_type;
|
||||
public:
|
||||
BOOST_STATIC_CONSTEXPR bool is_specialized = true;
|
||||
static number_type (min)() BOOST_NOEXCEPT { return 3.36210314311209350626267781732175260e-4932Q; }
|
||||
static number_type (max)() BOOST_NOEXCEPT { return 1.18973149535723176508575932662800702e4932Q; }
|
||||
static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
|
||||
BOOST_STATIC_CONSTEXPR int digits = 113;
|
||||
BOOST_STATIC_CONSTEXPR int digits10 = 33;
|
||||
BOOST_STATIC_CONSTEXPR int max_digits10 = 36;
|
||||
BOOST_STATIC_CONSTEXPR bool is_signed = true;
|
||||
BOOST_STATIC_CONSTEXPR bool is_integer = false;
|
||||
BOOST_STATIC_CONSTEXPR bool is_exact = false;
|
||||
BOOST_STATIC_CONSTEXPR int radix = 2;
|
||||
static number_type epsilon() { return 1.92592994438723585305597794258492732e-34Q; }
|
||||
static number_type round_error() { return 0.5; }
|
||||
BOOST_STATIC_CONSTEXPR int min_exponent = -16381;
|
||||
BOOST_STATIC_CONSTEXPR int min_exponent10 = min_exponent * 301L / 1000L;
|
||||
BOOST_STATIC_CONSTEXPR int max_exponent = 16384;
|
||||
BOOST_STATIC_CONSTEXPR int max_exponent10 = max_exponent * 301L / 1000L;
|
||||
BOOST_STATIC_CONSTEXPR bool has_infinity = true;
|
||||
BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = true;
|
||||
BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false;
|
||||
BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_present;
|
||||
BOOST_STATIC_CONSTEXPR bool has_denorm_loss = true;
|
||||
static number_type infinity() { return 1.0q / 0.0q; }
|
||||
static number_type quiet_NaN() { return number_type("nan"); }
|
||||
static number_type signaling_NaN() { return 0; }
|
||||
static number_type denorm_min() { return 6.475175119438025110924438958227646552e-4966Q; }
|
||||
BOOST_STATIC_CONSTEXPR bool is_iec559 = true;
|
||||
BOOST_STATIC_CONSTEXPR bool is_bounded = false;
|
||||
BOOST_STATIC_CONSTEXPR bool is_modulo = false;
|
||||
BOOST_STATIC_CONSTEXPR bool traps = false;
|
||||
BOOST_STATIC_CONSTEXPR bool tinyness_before = false;
|
||||
BOOST_STATIC_CONSTEXPR float_round_style round_style = round_to_nearest;
|
||||
};
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_specialized;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::digits;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::digits10;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::max_digits10;
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_signed;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_integer;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_exact;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::radix;
|
||||
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::min_exponent;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::max_exponent;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::min_exponent10;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::max_exponent10;
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_infinity;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_quiet_NaN;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_signaling_NaN;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_denorm_loss;
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_iec559;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_bounded;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_modulo;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::traps;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::tinyness_before;
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::round_style;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_denorm;
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,251 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_INTEGER_HPP
|
||||
#define BOOST_MP_INTEGER_HPP
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/multiprecision/detail/bitscan.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
|
||||
template <class Integer, class I2>
|
||||
typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
|
||||
multiply(Integer& result, const I2& a, const I2& b)
|
||||
{
|
||||
return result = static_cast<Integer>(a) * static_cast<Integer>(b);
|
||||
}
|
||||
template <class Integer, class I2>
|
||||
typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
|
||||
add(Integer& result, const I2& a, const I2& b)
|
||||
{
|
||||
return result = static_cast<Integer>(a) + static_cast<Integer>(b);
|
||||
}
|
||||
template <class Integer, class I2>
|
||||
typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
|
||||
subtract(Integer& result, const I2& a, const I2& b)
|
||||
{
|
||||
return result = static_cast<Integer>(a) - static_cast<Integer>(b);
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value>::type divide_qr(const Integer& x, const Integer& y, Integer& q, Integer& r)
|
||||
{
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
}
|
||||
|
||||
template <class I1, class I2>
|
||||
typename enable_if_c<is_integral<I1>::value && is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
|
||||
{
|
||||
return static_cast<I2>(x % val);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
//
|
||||
// Figure out the kind of integer that has twice as many bits as some builtin
|
||||
// integer type I. Use a native type if we can (including types which may not
|
||||
// be recognised by boost::int_t because they're larger than boost::long_long_type),
|
||||
// otherwise synthesize a cpp_int to do the job.
|
||||
//
|
||||
template <class I>
|
||||
struct double_integer
|
||||
{
|
||||
static const unsigned int_t_digits =
|
||||
2 * sizeof(I) <= sizeof(boost::long_long_type) ? std::numeric_limits<I>::digits * 2 : 1;
|
||||
|
||||
typedef typename mpl::if_c<
|
||||
2 * sizeof(I) <= sizeof(boost::long_long_type),
|
||||
typename mpl::if_c<
|
||||
is_signed<I>::value,
|
||||
typename boost::int_t<int_t_digits>::least,
|
||||
typename boost::uint_t<int_t_digits>::least
|
||||
>::type,
|
||||
typename mpl::if_c<
|
||||
2 * sizeof(I) <= sizeof(double_limb_type),
|
||||
typename mpl::if_c<
|
||||
is_signed<I>::value,
|
||||
signed_double_limb_type,
|
||||
double_limb_type
|
||||
>::type,
|
||||
number<cpp_int_backend<sizeof(I)*CHAR_BIT*2, sizeof(I)*CHAR_BIT*2, (is_signed<I>::value ? signed_magnitude : unsigned_magnitude), unchecked, void> >
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class I1, class I2, class I3>
|
||||
typename enable_if_c<is_integral<I1>::value && is_unsigned<I2>::value && is_integral<I3>::value, I1>::type
|
||||
powm(const I1& a, I2 b, I3 c)
|
||||
{
|
||||
typedef typename detail::double_integer<I1>::type double_type;
|
||||
|
||||
I1 x(1), y(a);
|
||||
double_type result;
|
||||
|
||||
while(b > 0)
|
||||
{
|
||||
if(b & 1)
|
||||
{
|
||||
multiply(result, x, y);
|
||||
x = integer_modulus(result, c);
|
||||
}
|
||||
multiply(result, y, y);
|
||||
y = integer_modulus(result, c);
|
||||
b >>= 1;
|
||||
}
|
||||
return x % c;
|
||||
}
|
||||
|
||||
template <class I1, class I2, class I3>
|
||||
inline typename enable_if_c<is_integral<I1>::value && is_signed<I2>::value && is_integral<I3>::value, I1>::type
|
||||
powm(const I1& a, I2 b, I3 c)
|
||||
{
|
||||
if(b < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
return powm(a, static_cast<typename make_unsigned<I2>::type>(b), c);
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, unsigned>::type lsb(const Integer& val)
|
||||
{
|
||||
if(val <= 0)
|
||||
{
|
||||
if(val == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
}
|
||||
return detail::find_lsb(val);
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, unsigned>::type msb(Integer val)
|
||||
{
|
||||
if(val <= 0)
|
||||
{
|
||||
if(val == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
}
|
||||
return detail::find_msb(val);
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, bool>::type bit_test(const Integer& val, unsigned index)
|
||||
{
|
||||
Integer mask = 1;
|
||||
if(index >= sizeof(Integer) * CHAR_BIT)
|
||||
return 0;
|
||||
if(index)
|
||||
mask <<= index;
|
||||
return val & mask ? true : false;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_set(Integer& val, unsigned index)
|
||||
{
|
||||
Integer mask = 1;
|
||||
if(index >= sizeof(Integer) * CHAR_BIT)
|
||||
return val;
|
||||
if(index)
|
||||
mask <<= index;
|
||||
val |= mask;
|
||||
return val;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_unset(Integer& val, unsigned index)
|
||||
{
|
||||
Integer mask = 1;
|
||||
if(index >= sizeof(Integer) * CHAR_BIT)
|
||||
return val;
|
||||
if(index)
|
||||
mask <<= index;
|
||||
val &= ~mask;
|
||||
return val;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_flip(Integer& val, unsigned index)
|
||||
{
|
||||
Integer mask = 1;
|
||||
if(index >= sizeof(Integer) * CHAR_BIT)
|
||||
return val;
|
||||
if(index)
|
||||
mask <<= index;
|
||||
val ^= mask;
|
||||
return val;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, Integer>::type sqrt(const Integer& x, Integer& r)
|
||||
{
|
||||
//
|
||||
// This is slow bit-by-bit integer square root, see for example
|
||||
// http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
|
||||
// There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
|
||||
// and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
|
||||
// at some point.
|
||||
//
|
||||
Integer s = 0;
|
||||
if(x == 0)
|
||||
{
|
||||
r = 0;
|
||||
return s;
|
||||
}
|
||||
int g = msb(x);
|
||||
if(g == 0)
|
||||
{
|
||||
r = 1;
|
||||
return s;
|
||||
}
|
||||
|
||||
Integer t = 0;
|
||||
r = x;
|
||||
g /= 2;
|
||||
bit_set(s, g);
|
||||
bit_set(t, 2 * g);
|
||||
r = x - t;
|
||||
--g;
|
||||
do
|
||||
{
|
||||
t = s;
|
||||
t <<= g + 1;
|
||||
bit_set(t, 2 * g);
|
||||
if(t <= r)
|
||||
{
|
||||
bit_set(s, g);
|
||||
r -= t;
|
||||
}
|
||||
--g;
|
||||
}
|
||||
while(g >= 0);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
typename enable_if_c<is_integral<Integer>::value, Integer>::type sqrt(const Integer& x)
|
||||
{
|
||||
Integer r;
|
||||
return sqrt(x, r);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,621 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MATH_LOGGED_ADAPTER_HPP
|
||||
#define BOOST_MATH_LOGGED_ADAPTER_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/extract_exponent_type.hpp>
|
||||
#include <boost/multiprecision/detail/integer_ops.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
|
||||
template <class Backend>
|
||||
inline void log_postfix_event(const Backend&, const char* /*event_description*/)
|
||||
{
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline void log_postfix_event(const Backend&, const T&, const char* /*event_description*/)
|
||||
{
|
||||
}
|
||||
template <class Backend>
|
||||
inline void log_prefix_event(const Backend&, const char* /*event_description*/)
|
||||
{
|
||||
}
|
||||
template <class Backend, class T>
|
||||
inline void log_prefix_event(const Backend&, const T&, const char* /*event_description*/)
|
||||
{
|
||||
}
|
||||
template <class Backend, class T, class U>
|
||||
inline void log_prefix_event(const Backend&, const T&, const U&, const char* /*event_description*/)
|
||||
{
|
||||
}
|
||||
template <class Backend, class T, class U, class V>
|
||||
inline void log_prefix_event(const Backend&, const T&, const U&, const V&, const char* /*event_description*/)
|
||||
{
|
||||
}
|
||||
|
||||
namespace backends{
|
||||
|
||||
template <class Backend>
|
||||
struct logged_adaptor
|
||||
{
|
||||
typedef typename Backend::signed_types signed_types;
|
||||
typedef typename Backend::unsigned_types unsigned_types;
|
||||
typedef typename Backend::float_types float_types;
|
||||
typedef typename extract_exponent_type<
|
||||
Backend, number_category<Backend>::value>::type exponent_type;
|
||||
|
||||
private:
|
||||
|
||||
Backend m_value;
|
||||
public:
|
||||
logged_adaptor()
|
||||
{
|
||||
log_postfix_event(m_value, "Default construct");
|
||||
}
|
||||
logged_adaptor(const logged_adaptor& o)
|
||||
{
|
||||
log_prefix_event(m_value, o.value(), "Copy construct");
|
||||
m_value = o.m_value;
|
||||
log_postfix_event(m_value, "Copy construct");
|
||||
}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
logged_adaptor(logged_adaptor&& o)
|
||||
{
|
||||
log_prefix_event(m_value, o.value(), "Move construct");
|
||||
m_value = static_cast<Backend&&>(o.m_value);
|
||||
log_postfix_event(m_value, "Move construct");
|
||||
}
|
||||
logged_adaptor& operator = (logged_adaptor&& o)
|
||||
{
|
||||
log_prefix_event(m_value, o.value(), "Move Assignment");
|
||||
m_value = static_cast<Backend&&>(o.m_value);
|
||||
log_postfix_event(m_value, "Move construct");
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
logged_adaptor& operator = (const logged_adaptor& o)
|
||||
{
|
||||
log_prefix_event(m_value, o.value(), "Assignment");
|
||||
m_value = o.m_value;
|
||||
log_postfix_event(m_value, "Copy construct");
|
||||
return *this;
|
||||
}
|
||||
template <class T>
|
||||
logged_adaptor(const T& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
|
||||
: m_value(i)
|
||||
{
|
||||
log_postfix_event(m_value, "construct from arithmetic type");
|
||||
}
|
||||
template <class T>
|
||||
logged_adaptor(const logged_adaptor<T>& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
|
||||
: m_value(i.value())
|
||||
{
|
||||
log_postfix_event(m_value, "construct from arithmetic type");
|
||||
}
|
||||
template <class T>
|
||||
typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, Backend>::value, logged_adaptor&>::type operator = (const T& i)
|
||||
{
|
||||
log_prefix_event(m_value, i, "Assignment from arithmetic type");
|
||||
m_value = i;
|
||||
log_postfix_event(m_value, "Assignment from arithmetic type");
|
||||
return *this;
|
||||
}
|
||||
logged_adaptor& operator = (const char* s)
|
||||
{
|
||||
log_prefix_event(m_value, s, "Assignment from string type");
|
||||
m_value = s;
|
||||
log_postfix_event(m_value, "Assignment from string type");
|
||||
return *this;
|
||||
}
|
||||
void swap(logged_adaptor& o)
|
||||
{
|
||||
log_prefix_event(m_value, o.value(), "swap");
|
||||
std::swap(m_value, o.value());
|
||||
log_postfix_event(m_value, "swap");
|
||||
}
|
||||
std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
|
||||
{
|
||||
log_prefix_event(m_value, "Conversion to string");
|
||||
std::string s = m_value.str(digits, f);
|
||||
log_postfix_event(m_value, s, "Conversion to string");
|
||||
return s;
|
||||
}
|
||||
void negate()
|
||||
{
|
||||
log_prefix_event(m_value, "negate");
|
||||
m_value.negate();
|
||||
log_postfix_event(m_value, "negate");
|
||||
}
|
||||
int compare(const logged_adaptor& o)const
|
||||
{
|
||||
log_prefix_event(m_value, o.value(), "compare");
|
||||
int r = m_value.compare(o.value());
|
||||
log_postfix_event(m_value, r, "compare");
|
||||
return r;
|
||||
}
|
||||
template <class T>
|
||||
int compare(const T& i)const
|
||||
{
|
||||
log_prefix_event(m_value, i, "compare");
|
||||
int r = m_value.compare(i);
|
||||
log_postfix_event(m_value, r, "compare");
|
||||
return r;
|
||||
}
|
||||
Backend& value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
const Backend& value()const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /*version*/)
|
||||
{
|
||||
log_prefix_event(m_value, "serialize");
|
||||
ar & m_value;
|
||||
log_postfix_event(m_value, "serialize");
|
||||
}
|
||||
static unsigned default_precision() BOOST_NOEXCEPT
|
||||
{
|
||||
return Backend::default_precision();
|
||||
}
|
||||
static void default_precision(unsigned v) BOOST_NOEXCEPT
|
||||
{
|
||||
Backend::default_precision(v);
|
||||
}
|
||||
unsigned precision()const BOOST_NOEXCEPT
|
||||
{
|
||||
return value().precision();
|
||||
}
|
||||
void precision(unsigned digits10) BOOST_NOEXCEPT
|
||||
{
|
||||
value().precision(digits10);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const T& unwrap_logged_type(const T& a) { return a; }
|
||||
template <class Backend>
|
||||
inline const Backend& unwrap_logged_type(const logged_adaptor<Backend>& a) { return a.value(); }
|
||||
|
||||
#define NON_MEMBER_OP1(name, str) \
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value());\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP2(name, str) \
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP3(name, str) \
|
||||
template <class Backend, class T, class U>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const U& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const T& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const logged_adaptor<Backend>& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}
|
||||
|
||||
#define NON_MEMBER_OP4(name, str) \
|
||||
template <class Backend, class T, class U, class V>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const U& b, const V& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b, const T& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const T& b, const logged_adaptor<Backend>& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend, class T>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const logged_adaptor<Backend>& b, const logged_adaptor<Backend>& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b, const logged_adaptor<Backend>& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class Backend, class T, class U>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const T& b, const U& c)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
|
||||
NON_MEMBER_OP2(add, "+=")
|
||||
NON_MEMBER_OP2(subtract, "-=")
|
||||
NON_MEMBER_OP2(multiply, "*=")
|
||||
NON_MEMBER_OP2(divide, "/=")
|
||||
|
||||
template <class Backend, class R>
|
||||
inline void eval_convert_to(R* result, const logged_adaptor<Backend>& val)
|
||||
{
|
||||
using default_ops::eval_convert_to;
|
||||
log_prefix_event(val.value(), "convert_to");
|
||||
eval_convert_to(result, val.value());
|
||||
log_postfix_event(val.value(), *result, "convert_to");
|
||||
}
|
||||
|
||||
template <class Backend, class Exp>
|
||||
inline void eval_frexp(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp* exp)
|
||||
{
|
||||
log_prefix_event(arg.value(), "frexp");
|
||||
eval_frexp(result.value(), arg.value(), exp);
|
||||
log_postfix_event(result.value(), *exp, "frexp");
|
||||
}
|
||||
|
||||
template <class Backend, class Exp>
|
||||
inline void eval_ldexp(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp exp)
|
||||
{
|
||||
log_prefix_event(arg.value(), "ldexp");
|
||||
eval_ldexp(result.value(), arg.value(), exp);
|
||||
log_postfix_event(result.value(), exp, "ldexp");
|
||||
}
|
||||
|
||||
template <class Backend, class Exp>
|
||||
inline void eval_scalbn(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp exp)
|
||||
{
|
||||
log_prefix_event(arg.value(), "scalbn");
|
||||
eval_scalbn(result.value(), arg.value(), exp);
|
||||
log_postfix_event(result.value(), exp, "scalbn");
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline typename Backend::exponent_type eval_ilogb(const logged_adaptor<Backend>& arg)
|
||||
{
|
||||
log_prefix_event(arg.value(), "ilogb");
|
||||
typename Backend::exponent_type r = eval_ilogb(arg.value());
|
||||
log_postfix_event(arg.value(), "ilogb");
|
||||
return r;
|
||||
}
|
||||
|
||||
NON_MEMBER_OP2(floor, "floor")
|
||||
NON_MEMBER_OP2(ceil, "ceil")
|
||||
NON_MEMBER_OP2(sqrt, "sqrt")
|
||||
|
||||
template <class Backend>
|
||||
inline int eval_fpclassify(const logged_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_fpclassify;
|
||||
log_prefix_event(arg.value(), "fpclassify");
|
||||
int r = eval_fpclassify(arg.value());
|
||||
log_postfix_event(arg.value(), r, "fpclassify");
|
||||
return r;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Optional arithmetic operations come next:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP3(add, "+")
|
||||
NON_MEMBER_OP3(subtract, "-")
|
||||
NON_MEMBER_OP3(multiply, "*")
|
||||
NON_MEMBER_OP3(divide, "/")
|
||||
NON_MEMBER_OP3(multiply_add, "fused-multiply-add")
|
||||
NON_MEMBER_OP3(multiply_subtract, "fused-multiply-subtract")
|
||||
NON_MEMBER_OP4(multiply_add, "fused-multiply-add")
|
||||
NON_MEMBER_OP4(multiply_subtract, "fused-multiply-subtract")
|
||||
|
||||
NON_MEMBER_OP1(increment, "increment")
|
||||
NON_MEMBER_OP1(decrement, "decrement")
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Optional integer operations come next:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP2(modulus, "%=")
|
||||
NON_MEMBER_OP3(modulus, "%")
|
||||
NON_MEMBER_OP2(bitwise_or, "|=")
|
||||
NON_MEMBER_OP3(bitwise_or, "|")
|
||||
NON_MEMBER_OP2(bitwise_and, "&=")
|
||||
NON_MEMBER_OP3(bitwise_and, "&")
|
||||
NON_MEMBER_OP2(bitwise_xor, "^=")
|
||||
NON_MEMBER_OP3(bitwise_xor, "^")
|
||||
NON_MEMBER_OP4(qr, "quotient-and-remainder")
|
||||
NON_MEMBER_OP2(complement, "~")
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_left_shift(logged_adaptor<Backend>& arg, std::size_t a)
|
||||
{
|
||||
using default_ops::eval_left_shift;
|
||||
log_prefix_event(arg.value(), a, "<<=");
|
||||
eval_left_shift(arg.value(), a);
|
||||
log_postfix_event(arg.value(), "<<=");
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_left_shift(logged_adaptor<Backend>& arg, const logged_adaptor<Backend>& a, std::size_t b)
|
||||
{
|
||||
using default_ops::eval_left_shift;
|
||||
log_prefix_event(arg.value(), a, b, "<<");
|
||||
eval_left_shift(arg.value(), a.value(), b);
|
||||
log_postfix_event(arg.value(), "<<");
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_right_shift(logged_adaptor<Backend>& arg, std::size_t a)
|
||||
{
|
||||
using default_ops::eval_right_shift;
|
||||
log_prefix_event(arg.value(), a, ">>=");
|
||||
eval_right_shift(arg.value(), a);
|
||||
log_postfix_event(arg.value(), ">>=");
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_right_shift(logged_adaptor<Backend>& arg, const logged_adaptor<Backend>& a, std::size_t b)
|
||||
{
|
||||
using default_ops::eval_right_shift;
|
||||
log_prefix_event(arg.value(), a, b, ">>");
|
||||
eval_right_shift(arg.value(), a.value(), b);
|
||||
log_postfix_event(arg.value(), ">>");
|
||||
}
|
||||
|
||||
template <class Backend, class T>
|
||||
inline unsigned eval_integer_modulus(const logged_adaptor<Backend>& arg, const T& a)
|
||||
{
|
||||
using default_ops::eval_integer_modulus;
|
||||
log_prefix_event(arg.value(), a, "integer-modulus");
|
||||
unsigned r = eval_integer_modulus(arg.value(), a);
|
||||
log_postfix_event(arg.value(), r, "integer-modulus");
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline unsigned eval_lsb(const logged_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
log_prefix_event(arg.value(), "least-significant-bit");
|
||||
unsigned r = eval_lsb(arg.value());
|
||||
log_postfix_event(arg.value(), r, "least-significant-bit");
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline unsigned eval_msb(const logged_adaptor<Backend>& arg)
|
||||
{
|
||||
using default_ops::eval_msb;
|
||||
log_prefix_event(arg.value(), "most-significant-bit");
|
||||
unsigned r = eval_msb(arg.value());
|
||||
log_postfix_event(arg.value(), r, "most-significant-bit");
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline bool eval_bit_test(const logged_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_test;
|
||||
log_prefix_event(arg.value(), a, "bit-test");
|
||||
bool r = eval_bit_test(arg.value(), a);
|
||||
log_postfix_event(arg.value(), r, "bit-test");
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline void eval_bit_set(const logged_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_set;
|
||||
log_prefix_event(arg.value(), a, "bit-set");
|
||||
eval_bit_set(arg.value(), a);
|
||||
log_postfix_event(arg.value(), arg, "bit-set");
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_bit_unset(const logged_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_unset;
|
||||
log_prefix_event(arg.value(), a, "bit-unset");
|
||||
eval_bit_unset(arg.value(), a);
|
||||
log_postfix_event(arg.value(), arg, "bit-unset");
|
||||
}
|
||||
template <class Backend>
|
||||
inline void eval_bit_flip(const logged_adaptor<Backend>& arg, unsigned a)
|
||||
{
|
||||
using default_ops::eval_bit_flip;
|
||||
log_prefix_event(arg.value(), a, "bit-flip");
|
||||
eval_bit_flip(arg.value(), a);
|
||||
log_postfix_event(arg.value(), arg, "bit-flip");
|
||||
}
|
||||
|
||||
NON_MEMBER_OP3(gcd, "gcd")
|
||||
NON_MEMBER_OP3(lcm, "lcm")
|
||||
NON_MEMBER_OP4(powm, "powm")
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* abs/fabs:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP2(abs, "abs")
|
||||
NON_MEMBER_OP2(fabs, "fabs")
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Floating point functions:
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
NON_MEMBER_OP2(trunc, "trunc")
|
||||
NON_MEMBER_OP2(round, "round")
|
||||
NON_MEMBER_OP2(exp, "exp")
|
||||
NON_MEMBER_OP2(log, "log")
|
||||
NON_MEMBER_OP2(log10, "log10")
|
||||
NON_MEMBER_OP2(sin, "sin")
|
||||
NON_MEMBER_OP2(cos, "cos")
|
||||
NON_MEMBER_OP2(tan, "tan")
|
||||
NON_MEMBER_OP2(asin, "asin")
|
||||
NON_MEMBER_OP2(acos, "acos")
|
||||
NON_MEMBER_OP2(atan, "atan")
|
||||
NON_MEMBER_OP2(sinh, "sinh")
|
||||
NON_MEMBER_OP2(cosh, "cosh")
|
||||
NON_MEMBER_OP2(tanh, "tanh")
|
||||
NON_MEMBER_OP2(logb, "logb")
|
||||
NON_MEMBER_OP3(fmod, "fmod")
|
||||
NON_MEMBER_OP3(pow, "pow")
|
||||
NON_MEMBER_OP3(atan2, "atan2")
|
||||
|
||||
template <class Backend>
|
||||
int eval_signbit(const logged_adaptor<Backend>& val)
|
||||
{
|
||||
using default_ops::eval_signbit;
|
||||
return eval_signbit(val.value());
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
std::size_t hash_value(const logged_adaptor<Backend>& val)
|
||||
{
|
||||
return hash_value(val.value());
|
||||
}
|
||||
|
||||
#define NON_MEMBER_COMPLEX_TO_REAL(name, str) \
|
||||
template <class B1, class B2>\
|
||||
inline void BOOST_JOIN(eval_, name)(logged_adaptor<B1>& result, const logged_adaptor<B2>& a)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(a.value(), a.value(), str);\
|
||||
BOOST_JOIN(eval_, name)(result.value(), a.value());\
|
||||
log_postfix_event(result.value(), str);\
|
||||
}\
|
||||
template <class B1, class B2>\
|
||||
inline void BOOST_JOIN(eval_, name)(B1& result, const logged_adaptor<B2>& a)\
|
||||
{\
|
||||
using default_ops::BOOST_JOIN(eval_, name);\
|
||||
log_prefix_event(a.value(), a.value(), str);\
|
||||
BOOST_JOIN(eval_, name)(result, a.value());\
|
||||
log_postfix_event(result, str);\
|
||||
}
|
||||
|
||||
NON_MEMBER_COMPLEX_TO_REAL(real, "real")
|
||||
NON_MEMBER_COMPLEX_TO_REAL(imag, "imag")
|
||||
|
||||
template <class T, class V, class U>
|
||||
inline void assign_components(logged_adaptor<T>& result, const V& v1, const U& v2)
|
||||
{
|
||||
assign_components(result.value(), v1, v2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace backends
|
||||
|
||||
using backends::logged_adaptor;
|
||||
|
||||
template<class Backend>
|
||||
struct number_category<backends::logged_adaptor<Backend> > : public number_category<Backend> {};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace std{
|
||||
|
||||
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<Backend>, ExpressionTemplates> >
|
||||
: public std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> >
|
||||
{
|
||||
typedef std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> > base_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<Backend>, ExpressionTemplates> number_type;
|
||||
public:
|
||||
static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
|
||||
static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
|
||||
static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
|
||||
static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
|
||||
static number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
|
||||
static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
|
||||
static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
|
||||
static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
|
||||
static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace policies{
|
||||
|
||||
template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
|
||||
struct precision< boost::multiprecision::number<boost::multiprecision::logged_adaptor<Backend>, ExpressionTemplates>, Policy>
|
||||
: public precision<boost::multiprecision::number<Backend, ExpressionTemplates>, Policy>
|
||||
{};
|
||||
|
||||
} // namespace policies
|
||||
|
||||
}} // namespaces boost::math
|
||||
|
||||
#undef NON_MEMBER_OP1
|
||||
#undef NON_MEMBER_OP2
|
||||
#undef NON_MEMBER_OP3
|
||||
#undef NON_MEMBER_OP4
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,226 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_MR_HPP
|
||||
#define BOOST_MP_MR_HPP
|
||||
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace detail{
|
||||
|
||||
template <class I>
|
||||
bool check_small_factors(const I& n)
|
||||
{
|
||||
static const boost::uint32_t small_factors1[] = {
|
||||
3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u };
|
||||
static const boost::uint32_t pp1 = 223092870u;
|
||||
|
||||
boost::uint32_t m1 = integer_modulus(n, pp1);
|
||||
|
||||
for(unsigned i = 0; i < sizeof(small_factors1) / sizeof(small_factors1[0]); ++i)
|
||||
{
|
||||
BOOST_ASSERT(pp1 % small_factors1[i] == 0);
|
||||
if(m1 % small_factors1[i] == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const boost::uint32_t small_factors2[] = {
|
||||
29u, 31u, 37u, 41u, 43u, 47u };
|
||||
static const boost::uint32_t pp2 = 2756205443u;
|
||||
|
||||
m1 = integer_modulus(n, pp2);
|
||||
|
||||
for(unsigned i = 0; i < sizeof(small_factors2) / sizeof(small_factors2[0]); ++i)
|
||||
{
|
||||
BOOST_ASSERT(pp2 % small_factors2[i] == 0);
|
||||
if(m1 % small_factors2[i] == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const boost::uint32_t small_factors3[] = {
|
||||
53u, 59u, 61u, 67u, 71u };
|
||||
static const boost::uint32_t pp3 = 907383479u;
|
||||
|
||||
m1 = integer_modulus(n, pp3);
|
||||
|
||||
for(unsigned i = 0; i < sizeof(small_factors3) / sizeof(small_factors3[0]); ++i)
|
||||
{
|
||||
BOOST_ASSERT(pp3 % small_factors3[i] == 0);
|
||||
if(m1 % small_factors3[i] == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const boost::uint32_t small_factors4[] = {
|
||||
73u, 79u, 83u, 89u, 97u };
|
||||
static const boost::uint32_t pp4 = 4132280413u;
|
||||
|
||||
m1 = integer_modulus(n, pp4);
|
||||
|
||||
for(unsigned i = 0; i < sizeof(small_factors4) / sizeof(small_factors4[0]); ++i)
|
||||
{
|
||||
BOOST_ASSERT(pp4 % small_factors4[i] == 0);
|
||||
if(m1 % small_factors4[i] == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const boost::uint32_t small_factors5[6][4] = {
|
||||
{ 101u, 103u, 107u, 109u },
|
||||
{ 113u, 127u, 131u, 137u },
|
||||
{ 139u, 149u, 151u, 157u },
|
||||
{ 163u, 167u, 173u, 179u },
|
||||
{ 181u, 191u, 193u, 197u },
|
||||
{ 199u, 211u, 223u, 227u }
|
||||
};
|
||||
static const boost::uint32_t pp5[6] =
|
||||
{
|
||||
121330189u,
|
||||
113u * 127u * 131u * 137u,
|
||||
139u * 149u * 151u * 157u,
|
||||
163u * 167u * 173u * 179u,
|
||||
181u * 191u * 193u * 197u,
|
||||
199u * 211u * 223u * 227u
|
||||
};
|
||||
|
||||
for(unsigned k = 0; k < sizeof(pp5) / sizeof(*pp5); ++k)
|
||||
{
|
||||
m1 = integer_modulus(n, pp5[k]);
|
||||
|
||||
for(unsigned i = 0; i < 4; ++i)
|
||||
{
|
||||
BOOST_ASSERT(pp5[k] % small_factors5[k][i] == 0);
|
||||
if(m1 % small_factors5[k][i] == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool is_small_prime(unsigned n)
|
||||
{
|
||||
static const unsigned char p[] =
|
||||
{
|
||||
3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u, 29u, 31u,
|
||||
37u, 41u, 43u, 47u, 53u, 59u, 61u, 67u, 71u, 73u,
|
||||
79u, 83u, 89u, 97u, 101u, 103u, 107u, 109u, 113u,
|
||||
127u, 131u, 137u, 139u, 149u, 151u, 157u, 163u,
|
||||
167u, 173u, 179u, 181u, 191u, 193u, 197u, 199u,
|
||||
211u, 223u, 227u
|
||||
};
|
||||
for(unsigned i = 0; i < sizeof(p) / sizeof(*p); ++i)
|
||||
{
|
||||
if(n == p[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class I>
|
||||
typename enable_if_c<is_convertible<I, unsigned>::value, unsigned>::type
|
||||
cast_to_unsigned(const I& val)
|
||||
{
|
||||
return static_cast<unsigned>(val);
|
||||
}
|
||||
template <class I>
|
||||
typename disable_if_c<is_convertible<I, unsigned>::value, unsigned>::type
|
||||
cast_to_unsigned(const I& val)
|
||||
{
|
||||
return val.template convert_to<unsigned>();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class I, class Engine>
|
||||
typename enable_if_c<number_category<I>::value == number_kind_integer, bool>::type
|
||||
miller_rabin_test(const I& n, unsigned trials, Engine& gen)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
typedef I number_type;
|
||||
|
||||
if (n == 2)
|
||||
return true; // Trivial special case.
|
||||
if(bit_test(n, 0) == 0)
|
||||
return false; // n is even
|
||||
if(n <= 227)
|
||||
return detail::is_small_prime(detail::cast_to_unsigned(n));
|
||||
|
||||
if(!detail::check_small_factors(n))
|
||||
return false;
|
||||
|
||||
number_type nm1 = n - 1;
|
||||
//
|
||||
// Begin with a single Fermat test - it excludes a lot of candidates:
|
||||
//
|
||||
number_type q(228), x, y; // We know n is greater than this, as we've excluded small factors
|
||||
x = powm(q, nm1, n);
|
||||
if(x != 1u)
|
||||
return false;
|
||||
|
||||
q = n - 1;
|
||||
unsigned k = lsb(q);
|
||||
q >>= k;
|
||||
|
||||
// Declare our random number generator:
|
||||
boost::random::uniform_int_distribution<number_type> dist(2, n - 2);
|
||||
//
|
||||
// Execute the trials:
|
||||
//
|
||||
for(unsigned i = 0; i < trials; ++i)
|
||||
{
|
||||
x = dist(gen);
|
||||
y = powm(x, q, n);
|
||||
unsigned j = 0;
|
||||
while(true)
|
||||
{
|
||||
if(y == nm1)
|
||||
break;
|
||||
if(y == 1)
|
||||
{
|
||||
if(j == 0)
|
||||
break;
|
||||
return false; // test failed
|
||||
}
|
||||
if(++j == k)
|
||||
return false; // failed
|
||||
y = powm(y, 2, n);
|
||||
}
|
||||
}
|
||||
return true; // Yeheh! probably prime.
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class I>
|
||||
typename enable_if_c<number_category<I>::value == number_kind_integer, bool>::type
|
||||
miller_rabin_test(const I& x, unsigned trials)
|
||||
{
|
||||
static mt19937 gen;
|
||||
return miller_rabin_test(x, trials, gen);
|
||||
}
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Engine>
|
||||
bool miller_rabin_test(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4> & n, unsigned trials, Engine& gen)
|
||||
{
|
||||
typedef typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type number_type;
|
||||
return miller_rabin_test(number_type(n), trials, gen);
|
||||
}
|
||||
|
||||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
bool miller_rabin_test(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4> & n, unsigned trials)
|
||||
{
|
||||
typedef typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type number_type;
|
||||
return miller_rabin_test(number_type(n), trials);
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright Jens Maurer 2006-1011
|
||||
// Copyright Steven Watanabe 2011
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_RANDOM_HPP
|
||||
#define BOOST_MP_RANDOM_HPP
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
# pragma message("NOTE: Use of this header (boost/multiprecision/random.hpp) is deprecated: please use the random number library headers directly.")
|
||||
#endif
|
||||
|
||||
|
||||
#include <boost/random.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,367 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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_
|
||||
|
||||
#ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP
|
||||
#define BOOST_MATH_RATIONAL_ADAPTER_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4512 4127)
|
||||
#endif
|
||||
#include <boost/rational.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace backends{
|
||||
|
||||
template <class IntBackend>
|
||||
struct rational_adaptor
|
||||
{
|
||||
typedef number<IntBackend> integer_type;
|
||||
typedef boost::rational<integer_type> rational_type;
|
||||
|
||||
typedef typename IntBackend::signed_types signed_types;
|
||||
typedef typename IntBackend::unsigned_types unsigned_types;
|
||||
typedef typename IntBackend::float_types float_types;
|
||||
|
||||
rational_adaptor() BOOST_MP_NOEXCEPT_IF(noexcept(rational_type())) {}
|
||||
rational_adaptor(const rational_adaptor& o) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<const rational_type&>()))
|
||||
{
|
||||
m_value = o.m_value;
|
||||
}
|
||||
rational_adaptor(const IntBackend& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<const IntBackend&>()))) : m_value(o) {}
|
||||
|
||||
template <class U>
|
||||
rational_adaptor(const U& u, typename enable_if_c<is_convertible<U, IntBackend>::value>::type* = 0)
|
||||
: m_value(static_cast<integer_type>(u)){}
|
||||
template <class U>
|
||||
explicit rational_adaptor(const U& u,
|
||||
typename enable_if_c<
|
||||
boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_convertible<U, IntBackend>::value
|
||||
>::type* = 0)
|
||||
: m_value(IntBackend(u)){}
|
||||
template <class U>
|
||||
typename enable_if_c<(boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_arithmetic<U>::value), rational_adaptor&>::type operator = (const U& u)
|
||||
{
|
||||
m_value = IntBackend(u);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
rational_adaptor(rational_adaptor&& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<rational_type>()))) : m_value(static_cast<rational_type&&>(o.m_value)) {}
|
||||
rational_adaptor(IntBackend&& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<IntBackend>()))) : m_value(static_cast<IntBackend&&>(o)) {}
|
||||
rational_adaptor& operator = (rational_adaptor&& o) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<rational_type>()))
|
||||
{
|
||||
m_value = static_cast<rational_type&&>(o.m_value);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
rational_adaptor& operator = (const rational_adaptor& o)
|
||||
{
|
||||
m_value = o.m_value;
|
||||
return *this;
|
||||
}
|
||||
rational_adaptor& operator = (const IntBackend& o)
|
||||
{
|
||||
m_value = o;
|
||||
return *this;
|
||||
}
|
||||
template <class Int>
|
||||
typename enable_if<is_integral<Int>, rational_adaptor&>::type operator = (Int i)
|
||||
{
|
||||
m_value = i;
|
||||
return *this;
|
||||
}
|
||||
template <class Float>
|
||||
typename enable_if<is_floating_point<Float>, rational_adaptor&>::type operator = (Float i)
|
||||
{
|
||||
int e;
|
||||
Float f = std::frexp(i, &e);
|
||||
f = std::ldexp(f, std::numeric_limits<Float>::digits);
|
||||
e -= std::numeric_limits<Float>::digits;
|
||||
integer_type num(f);
|
||||
integer_type denom(1u);
|
||||
if(e > 0)
|
||||
{
|
||||
num <<= e;
|
||||
}
|
||||
else if(e < 0)
|
||||
{
|
||||
denom <<= -e;
|
||||
}
|
||||
m_value.assign(num, denom);
|
||||
return *this;
|
||||
}
|
||||
rational_adaptor& operator = (const char* s)
|
||||
{
|
||||
std::string s1;
|
||||
multiprecision::number<IntBackend> v1, v2;
|
||||
char c;
|
||||
bool have_hex = false;
|
||||
const char* p = s; // saved for later
|
||||
|
||||
while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
|
||||
{
|
||||
if(c == 'x' || c == 'X')
|
||||
have_hex = true;
|
||||
s1.append(1, c);
|
||||
++s;
|
||||
}
|
||||
v1.assign(s1);
|
||||
s1.erase();
|
||||
if(c == '/')
|
||||
{
|
||||
++s;
|
||||
while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
|
||||
{
|
||||
if(c == 'x' || c == 'X')
|
||||
have_hex = true;
|
||||
s1.append(1, c);
|
||||
++s;
|
||||
}
|
||||
v2.assign(s1);
|
||||
}
|
||||
else
|
||||
v2 = 1;
|
||||
if(*s)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Could not parse the string \"") + p + std::string("\" as a valid rational number.")));
|
||||
}
|
||||
data().assign(v1, v2);
|
||||
return *this;
|
||||
}
|
||||
void swap(rational_adaptor& o)
|
||||
{
|
||||
std::swap(m_value, o.m_value);
|
||||
}
|
||||
std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
|
||||
{
|
||||
//
|
||||
// We format the string ourselves so we can match what GMP's mpq type does:
|
||||
//
|
||||
std::string result = data().numerator().str(digits, f);
|
||||
if(data().denominator() != 1)
|
||||
{
|
||||
result.append(1, '/');
|
||||
result.append(data().denominator().str(digits, f));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void negate()
|
||||
{
|
||||
m_value = -m_value;
|
||||
}
|
||||
int compare(const rational_adaptor& o)const
|
||||
{
|
||||
return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
|
||||
}
|
||||
template <class Arithmatic>
|
||||
typename enable_if_c<is_arithmetic<Arithmatic>::value && !is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
|
||||
{
|
||||
return m_value > i ? 1 : (m_value < i ? -1 : 0);
|
||||
}
|
||||
template <class Arithmatic>
|
||||
typename enable_if_c<is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
|
||||
{
|
||||
rational_adaptor r;
|
||||
r = i;
|
||||
return this->compare(r);
|
||||
}
|
||||
rational_type& data() { return m_value; }
|
||||
const rational_type& data()const { return m_value; }
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const mpl::true_&)
|
||||
{
|
||||
// Saving
|
||||
integer_type n(m_value.numerator()), d(m_value.denominator());
|
||||
ar & n;
|
||||
ar & d;
|
||||
}
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const mpl::false_&)
|
||||
{
|
||||
// Loading
|
||||
integer_type n, d;
|
||||
ar & n;
|
||||
ar & d;
|
||||
m_value.assign(n, d);
|
||||
}
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int /*version*/)
|
||||
{
|
||||
typedef typename Archive::is_saving tag;
|
||||
serialize(ar, tag());
|
||||
}
|
||||
private:
|
||||
rational_type m_value;
|
||||
};
|
||||
|
||||
template <class IntBackend>
|
||||
inline void eval_add(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
|
||||
{
|
||||
result.data() += o.data();
|
||||
}
|
||||
template <class IntBackend>
|
||||
inline void eval_subtract(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
|
||||
{
|
||||
result.data() -= o.data();
|
||||
}
|
||||
template <class IntBackend>
|
||||
inline void eval_multiply(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
|
||||
{
|
||||
result.data() *= o.data();
|
||||
}
|
||||
template <class IntBackend>
|
||||
inline void eval_divide(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
if(eval_is_zero(o))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero."));
|
||||
}
|
||||
result.data() /= o.data();
|
||||
}
|
||||
|
||||
template <class R, class IntBackend>
|
||||
inline typename enable_if_c<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
|
||||
{
|
||||
//
|
||||
// The generic conversion is as good as anything we can write here:
|
||||
//
|
||||
::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend);
|
||||
}
|
||||
|
||||
template <class R, class IntBackend>
|
||||
inline typename enable_if_c<(number_category<R>::value != number_kind_integer) && (number_category<R>::value != number_kind_floating_point)>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
|
||||
{
|
||||
typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
|
||||
comp_t num(backend.data().numerator());
|
||||
comp_t denom(backend.data().denominator());
|
||||
*result = num.template convert_to<R>();
|
||||
*result /= denom.template convert_to<R>();
|
||||
}
|
||||
|
||||
template <class R, class IntBackend>
|
||||
inline typename enable_if_c<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
|
||||
{
|
||||
typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
|
||||
comp_t t = backend.data().numerator();
|
||||
t /= backend.data().denominator();
|
||||
*result = t.template convert_to<R>();
|
||||
}
|
||||
|
||||
template <class IntBackend>
|
||||
inline bool eval_is_zero(const rational_adaptor<IntBackend>& val)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
return eval_is_zero(val.data().numerator().backend());
|
||||
}
|
||||
template <class IntBackend>
|
||||
inline int eval_get_sign(const rational_adaptor<IntBackend>& val)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
return eval_get_sign(val.data().numerator().backend());
|
||||
}
|
||||
|
||||
template<class IntBackend, class V>
|
||||
inline void assign_components(rational_adaptor<IntBackend>& result, const V& v1, const V& v2)
|
||||
{
|
||||
result.data().assign(v1, v2);
|
||||
}
|
||||
|
||||
template <class IntBackend>
|
||||
inline std::size_t hash_value(const rational_adaptor<IntBackend>& val)
|
||||
{
|
||||
std::size_t result = hash_value(val.data().numerator());
|
||||
boost::hash_combine(result, val.data().denominator());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace backends
|
||||
|
||||
template<class IntBackend>
|
||||
struct expression_template_default<backends::rational_adaptor<IntBackend> > : public expression_template_default<IntBackend> {};
|
||||
|
||||
template<class IntBackend>
|
||||
struct number_category<backends::rational_adaptor<IntBackend> > : public mpl::int_<number_kind_rational>{};
|
||||
|
||||
using boost::multiprecision::backends::rational_adaptor;
|
||||
|
||||
template <class Backend, expression_template_option ExpressionTemplates>
|
||||
struct component_type<number<backends::rational_adaptor<Backend>, ExpressionTemplates> >
|
||||
{
|
||||
typedef number<Backend, ExpressionTemplates> type;
|
||||
};
|
||||
|
||||
template <class IntBackend, expression_template_option ET>
|
||||
inline number<IntBackend, ET> numerator(const number<rational_adaptor<IntBackend>, ET>& val)
|
||||
{
|
||||
return val.backend().data().numerator();
|
||||
}
|
||||
template <class IntBackend, expression_template_option ET>
|
||||
inline number<IntBackend, ET> denominator(const number<rational_adaptor<IntBackend>, ET>& val)
|
||||
{
|
||||
return val.backend().data().denominator();
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_SFINAE_EXPR
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<class U, class IntBackend>
|
||||
struct is_explicitly_convertible<U, rational_adaptor<IntBackend> > : public is_explicitly_convertible<U, IntBackend> {};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}} // namespaces
|
||||
|
||||
|
||||
namespace std{
|
||||
|
||||
template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> > : public std::numeric_limits<boost::multiprecision::number<IntBackend, ExpressionTemplates> >
|
||||
{
|
||||
typedef std::numeric_limits<boost::multiprecision::number<IntBackend> > base_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend> > number_type;
|
||||
public:
|
||||
BOOST_STATIC_CONSTEXPR bool is_integer = false;
|
||||
BOOST_STATIC_CONSTEXPR bool is_exact = true;
|
||||
BOOST_STATIC_CONSTEXPR number_type (min)() { return (base_type::min)(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type (max)() { return (base_type::max)(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type lowest() { return -(max)(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type epsilon() { return base_type::epsilon(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type round_error() { return epsilon() / 2; }
|
||||
BOOST_STATIC_CONSTEXPR number_type infinity() { return base_type::infinity(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return base_type::quiet_NaN(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return base_type::signaling_NaN(); }
|
||||
BOOST_STATIC_CONSTEXPR number_type denorm_min() { return base_type::denorm_min(); }
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
|
||||
template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_integer;
|
||||
template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_exact;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,781 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_MP_TOMMATH_BACKEND_HPP
|
||||
#define BOOST_MATH_MP_TOMMATH_BACKEND_HPP
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
#include <boost/multiprecision/rational_adaptor.hpp>
|
||||
#include <boost/multiprecision/detail/integer_ops.hpp>
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <tommath.h>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <climits>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
namespace detail{
|
||||
|
||||
inline void check_tommath_result(unsigned v)
|
||||
{
|
||||
if(v != MP_OKAY)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(mp_error_to_string(v)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct tommath_int;
|
||||
|
||||
void eval_multiply(tommath_int& t, const tommath_int& o);
|
||||
void eval_add(tommath_int& t, const tommath_int& o);
|
||||
|
||||
struct tommath_int
|
||||
{
|
||||
typedef mpl::list<boost::int32_t, boost::long_long_type> signed_types;
|
||||
typedef mpl::list<boost::uint32_t, boost::ulong_long_type> unsigned_types;
|
||||
typedef mpl::list<long double> float_types;
|
||||
|
||||
tommath_int()
|
||||
{
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
}
|
||||
tommath_int(const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_init_copy(&m_data, const_cast< ::mp_int*>(&o.m_data)));
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
tommath_int(tommath_int&& o) BOOST_NOEXCEPT
|
||||
{
|
||||
m_data = o.m_data;
|
||||
o.m_data.dp = 0;
|
||||
}
|
||||
tommath_int& operator = (tommath_int&& o)
|
||||
{
|
||||
mp_exch(&m_data, &o.m_data);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
tommath_int& operator = (const tommath_int& o)
|
||||
{
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
if(o.m_data.dp)
|
||||
detail::check_tommath_result(mp_copy(const_cast< ::mp_int*>(&o.m_data), &m_data));
|
||||
return *this;
|
||||
}
|
||||
tommath_int& operator = (boost::ulong_long_type i)
|
||||
{
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
boost::ulong_long_type mask = ((1uLL << std::numeric_limits<unsigned>::digits) - 1);
|
||||
unsigned shift = 0;
|
||||
::mp_int t;
|
||||
detail::check_tommath_result(mp_init(&t));
|
||||
mp_zero(&m_data);
|
||||
while(i)
|
||||
{
|
||||
detail::check_tommath_result(mp_set_int(&t, static_cast<unsigned>(i & mask)));
|
||||
if(shift)
|
||||
detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
|
||||
detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
|
||||
shift += std::numeric_limits<unsigned>::digits;
|
||||
i >>= std::numeric_limits<unsigned>::digits;
|
||||
}
|
||||
mp_clear(&t);
|
||||
return *this;
|
||||
}
|
||||
tommath_int& operator = (boost::long_long_type i)
|
||||
{
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
bool neg = i < 0;
|
||||
*this = boost::multiprecision::detail::unsigned_abs(i);
|
||||
if(neg)
|
||||
detail::check_tommath_result(mp_neg(&m_data, &m_data));
|
||||
return *this;
|
||||
}
|
||||
//
|
||||
// Note that although mp_set_int takes an unsigned long as an argument
|
||||
// it only sets the first 32-bits to the result, and ignores the rest.
|
||||
// So use uint32_t as the largest type to pass to this function.
|
||||
//
|
||||
tommath_int& operator = (boost::uint32_t i)
|
||||
{
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
detail::check_tommath_result((mp_set_int(&m_data, i)));
|
||||
return *this;
|
||||
}
|
||||
tommath_int& operator = (boost::int32_t i)
|
||||
{
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
bool neg = i < 0;
|
||||
*this = boost::multiprecision::detail::unsigned_abs(i);
|
||||
if(neg)
|
||||
detail::check_tommath_result(mp_neg(&m_data, &m_data));
|
||||
return *this;
|
||||
}
|
||||
tommath_int& operator = (long double a)
|
||||
{
|
||||
using std::frexp;
|
||||
using std::ldexp;
|
||||
using std::floor;
|
||||
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
|
||||
if (a == 0) {
|
||||
detail::check_tommath_result(mp_set_int(&m_data, 0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (a == 1) {
|
||||
detail::check_tommath_result(mp_set_int(&m_data, 1));
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!(boost::math::isinf)(a));
|
||||
BOOST_ASSERT(!(boost::math::isnan)(a));
|
||||
|
||||
int e;
|
||||
long double f, term;
|
||||
detail::check_tommath_result(mp_set_int(&m_data, 0u));
|
||||
::mp_int t;
|
||||
detail::check_tommath_result(mp_init(&t));
|
||||
|
||||
f = frexp(a, &e);
|
||||
|
||||
static const int shift = std::numeric_limits<int>::digits - 1;
|
||||
|
||||
while(f)
|
||||
{
|
||||
// extract int sized bits from f:
|
||||
f = ldexp(f, shift);
|
||||
term = floor(f);
|
||||
e -= shift;
|
||||
detail::check_tommath_result(mp_mul_2d(&m_data, shift, &m_data));
|
||||
if(term > 0)
|
||||
{
|
||||
detail::check_tommath_result(mp_set_int(&t, static_cast<int>(term)));
|
||||
detail::check_tommath_result(mp_add(&m_data, &t, &m_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::check_tommath_result(mp_set_int(&t, static_cast<int>(-term)));
|
||||
detail::check_tommath_result(mp_sub(&m_data, &t, &m_data));
|
||||
}
|
||||
f -= term;
|
||||
}
|
||||
if(e > 0)
|
||||
detail::check_tommath_result(mp_mul_2d(&m_data, e, &m_data));
|
||||
else if(e < 0)
|
||||
{
|
||||
tommath_int t2;
|
||||
detail::check_tommath_result(mp_div_2d(&m_data, -e, &m_data, &t2.data()));
|
||||
}
|
||||
mp_clear(&t);
|
||||
return *this;
|
||||
}
|
||||
tommath_int& operator = (const char* s)
|
||||
{
|
||||
//
|
||||
// We don't use libtommath's own routine because it doesn't error check the input :-(
|
||||
//
|
||||
if(m_data.dp == 0)
|
||||
detail::check_tommath_result(mp_init(&m_data));
|
||||
std::size_t n = s ? std::strlen(s) : 0;
|
||||
*this = static_cast<boost::uint32_t>(0u);
|
||||
unsigned radix = 10;
|
||||
bool isneg = false;
|
||||
if(n && (*s == '-'))
|
||||
{
|
||||
--n;
|
||||
++s;
|
||||
isneg = true;
|
||||
}
|
||||
if(n && (*s == '0'))
|
||||
{
|
||||
if((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
|
||||
{
|
||||
radix = 16;
|
||||
s +=2;
|
||||
n -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
radix = 8;
|
||||
n -= 1;
|
||||
}
|
||||
}
|
||||
if(n)
|
||||
{
|
||||
if(radix == 8 || radix == 16)
|
||||
{
|
||||
unsigned shift = radix == 8 ? 3 : 4;
|
||||
unsigned block_count = DIGIT_BIT / shift;
|
||||
unsigned block_shift = shift * block_count;
|
||||
boost::ulong_long_type val, block;
|
||||
while(*s)
|
||||
{
|
||||
block = 0;
|
||||
for(unsigned i = 0; (i < block_count); ++i)
|
||||
{
|
||||
if(*s >= '0' && *s <= '9')
|
||||
val = *s - '0';
|
||||
else if(*s >= 'a' && *s <= 'f')
|
||||
val = 10 + *s - 'a';
|
||||
else if(*s >= 'A' && *s <= 'F')
|
||||
val = 10 + *s - 'A';
|
||||
else
|
||||
val = 400;
|
||||
if(val > radix)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
|
||||
}
|
||||
block <<= shift;
|
||||
block |= val;
|
||||
if(!*++s)
|
||||
{
|
||||
// final shift is different:
|
||||
block_shift = (i + 1) * shift;
|
||||
break;
|
||||
}
|
||||
}
|
||||
detail::check_tommath_result(mp_mul_2d(&data(), block_shift, &data()));
|
||||
if(data().used)
|
||||
data().dp[0] |= block;
|
||||
else
|
||||
*this = block;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Base 10, we extract blocks of size 10^9 at a time, that way
|
||||
// the number of multiplications is kept to a minimum:
|
||||
boost::uint32_t block_mult = 1000000000;
|
||||
while(*s)
|
||||
{
|
||||
boost::uint32_t block = 0;
|
||||
for(unsigned i = 0; i < 9; ++i)
|
||||
{
|
||||
boost::uint32_t val;
|
||||
if(*s >= '0' && *s <= '9')
|
||||
val = *s - '0';
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected character encountered in input."));
|
||||
block *= 10;
|
||||
block += val;
|
||||
if(!*++s)
|
||||
{
|
||||
static const boost::uint32_t block_multiplier[9] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
block_mult = block_multiplier[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
tommath_int t;
|
||||
t = block_mult;
|
||||
eval_multiply(*this, t);
|
||||
t = block;
|
||||
eval_add(*this, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isneg)
|
||||
this->negate();
|
||||
return *this;
|
||||
}
|
||||
std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f)const
|
||||
{
|
||||
BOOST_ASSERT(m_data.dp);
|
||||
int base = 10;
|
||||
if((f & std::ios_base::oct) == std::ios_base::oct)
|
||||
base = 8;
|
||||
else if((f & std::ios_base::hex) == std::ios_base::hex)
|
||||
base = 16;
|
||||
//
|
||||
// sanity check, bases 8 and 16 are only available for positive numbers:
|
||||
//
|
||||
if((base != 10) && m_data.sign)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
|
||||
int s;
|
||||
detail::check_tommath_result(mp_radix_size(const_cast< ::mp_int*>(&m_data), base, &s));
|
||||
boost::scoped_array<char> a(new char[s+1]);
|
||||
detail::check_tommath_result(mp_toradix_n(const_cast< ::mp_int*>(&m_data), a.get(), base, s+1));
|
||||
std::string result = a.get();
|
||||
if((base != 10) && (f & std::ios_base::showbase))
|
||||
{
|
||||
int pos = result[0] == '-' ? 1 : 0;
|
||||
const char* pp = base == 8 ? "0" : "0x";
|
||||
result.insert(static_cast<std::string::size_type>(pos), pp);
|
||||
}
|
||||
if((f & std::ios_base::showpos) && (result[0] != '-'))
|
||||
result.insert(static_cast<std::string::size_type>(0), 1, '+');
|
||||
return result;
|
||||
}
|
||||
~tommath_int()
|
||||
{
|
||||
if(m_data.dp)
|
||||
mp_clear(&m_data);
|
||||
}
|
||||
void negate()
|
||||
{
|
||||
BOOST_ASSERT(m_data.dp);
|
||||
mp_neg(&m_data, &m_data);
|
||||
}
|
||||
int compare(const tommath_int& o)const
|
||||
{
|
||||
BOOST_ASSERT(m_data.dp && o.m_data.dp);
|
||||
return mp_cmp(const_cast< ::mp_int*>(&m_data), const_cast< ::mp_int*>(&o.m_data));
|
||||
}
|
||||
template <class V>
|
||||
int compare(V v)const
|
||||
{
|
||||
tommath_int d;
|
||||
tommath_int t(*this);
|
||||
detail::check_tommath_result(mp_shrink(&t.data()));
|
||||
d = v;
|
||||
return t.compare(d);
|
||||
}
|
||||
::mp_int& data()
|
||||
{
|
||||
BOOST_ASSERT(m_data.dp);
|
||||
return m_data;
|
||||
}
|
||||
const ::mp_int& data()const
|
||||
{
|
||||
BOOST_ASSERT(m_data.dp);
|
||||
return m_data;
|
||||
}
|
||||
void swap(tommath_int& o)BOOST_NOEXCEPT
|
||||
{
|
||||
mp_exch(&m_data, &o.data());
|
||||
}
|
||||
protected:
|
||||
::mp_int m_data;
|
||||
};
|
||||
|
||||
#define BOOST_MP_TOMMATH_BIT_OP_CHECK(x)\
|
||||
if(SIGN(&x.data()))\
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
|
||||
|
||||
int eval_get_sign(const tommath_int& val);
|
||||
|
||||
inline void eval_add(tommath_int& t, const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
}
|
||||
inline void eval_subtract(tommath_int& t, const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_sub(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
}
|
||||
inline void eval_multiply(tommath_int& t, const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_mul(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
}
|
||||
inline void eval_divide(tommath_int& t, const tommath_int& o)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
tommath_int temp;
|
||||
if(eval_is_zero(o))
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
|
||||
detail::check_tommath_result(mp_div(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data(), &temp.data()));
|
||||
}
|
||||
inline void eval_modulus(tommath_int& t, const tommath_int& o)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
if(eval_is_zero(o))
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
|
||||
bool neg = eval_get_sign(t) < 0;
|
||||
bool neg2 = eval_get_sign(o) < 0;
|
||||
detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
if((neg != neg2) && (eval_get_sign(t) != 0))
|
||||
{
|
||||
t.negate();
|
||||
detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
t.negate();
|
||||
}
|
||||
else if(neg && (t.compare(o) == 0))
|
||||
{
|
||||
mp_zero(&t.data());
|
||||
}
|
||||
}
|
||||
template <class UI>
|
||||
inline void eval_left_shift(tommath_int& t, UI i)
|
||||
{
|
||||
detail::check_tommath_result(mp_mul_2d(&t.data(), static_cast<unsigned>(i), &t.data()));
|
||||
}
|
||||
template <class UI>
|
||||
inline void eval_right_shift(tommath_int& t, UI i)
|
||||
{
|
||||
using default_ops::eval_increment;
|
||||
using default_ops::eval_decrement;
|
||||
bool neg = eval_get_sign(t) < 0;
|
||||
tommath_int d;
|
||||
if(neg)
|
||||
eval_increment(t);
|
||||
detail::check_tommath_result(mp_div_2d(&t.data(), static_cast<unsigned>(i), &t.data(), &d.data()));
|
||||
if(neg)
|
||||
eval_decrement(t);
|
||||
}
|
||||
template <class UI>
|
||||
inline void eval_left_shift(tommath_int& t, const tommath_int& v, UI i)
|
||||
{
|
||||
detail::check_tommath_result(mp_mul_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned>(i), &t.data()));
|
||||
}
|
||||
/*
|
||||
template <class UI>
|
||||
inline void eval_right_shift(tommath_int& t, const tommath_int& v, UI i)
|
||||
{
|
||||
tommath_int d;
|
||||
detail::check_tommath_result(mp_div_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned long>(i), &t.data(), &d.data()));
|
||||
}
|
||||
*/
|
||||
inline void eval_bitwise_and(tommath_int& result, const tommath_int& v)
|
||||
{
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
|
||||
detail::check_tommath_result(mp_and(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
|
||||
}
|
||||
|
||||
inline void eval_bitwise_or(tommath_int& result, const tommath_int& v)
|
||||
{
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
|
||||
detail::check_tommath_result(mp_or(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
|
||||
}
|
||||
|
||||
inline void eval_bitwise_xor(tommath_int& result, const tommath_int& v)
|
||||
{
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
|
||||
detail::check_tommath_result(mp_xor(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
|
||||
}
|
||||
|
||||
inline void eval_add(tommath_int& t, const tommath_int& p, const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_add(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
}
|
||||
inline void eval_subtract(tommath_int& t, const tommath_int& p, const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_sub(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
}
|
||||
inline void eval_multiply(tommath_int& t, const tommath_int& p, const tommath_int& o)
|
||||
{
|
||||
detail::check_tommath_result(mp_mul(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
}
|
||||
inline void eval_divide(tommath_int& t, const tommath_int& p, const tommath_int& o)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
tommath_int d;
|
||||
if(eval_is_zero(o))
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
|
||||
detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data(), &d.data()));
|
||||
}
|
||||
inline void eval_modulus(tommath_int& t, const tommath_int& p, const tommath_int& o)
|
||||
{
|
||||
using default_ops::eval_is_zero;
|
||||
if(eval_is_zero(o))
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
|
||||
bool neg = eval_get_sign(p) < 0;
|
||||
bool neg2 = eval_get_sign(o) < 0;
|
||||
detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
if((neg != neg2) && (eval_get_sign(t) != 0))
|
||||
{
|
||||
t.negate();
|
||||
detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
|
||||
t.negate();
|
||||
}
|
||||
else if(neg && (t.compare(o) == 0))
|
||||
{
|
||||
mp_zero(&t.data());
|
||||
}
|
||||
}
|
||||
|
||||
inline void eval_bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)
|
||||
{
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
|
||||
detail::check_tommath_result(mp_and(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
|
||||
}
|
||||
|
||||
inline void eval_bitwise_or(tommath_int& result, const tommath_int& u, const tommath_int& v)
|
||||
{
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
|
||||
detail::check_tommath_result(mp_or(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
|
||||
}
|
||||
|
||||
inline void eval_bitwise_xor(tommath_int& result, const tommath_int& u, const tommath_int& v)
|
||||
{
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
|
||||
BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
|
||||
detail::check_tommath_result(mp_xor(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
|
||||
}
|
||||
/*
|
||||
inline void eval_complement(tommath_int& result, const tommath_int& u)
|
||||
{
|
||||
//
|
||||
// Although this code works, it doesn't really do what the user might expect....
|
||||
// and it's hard to see how it ever could. Disabled for now:
|
||||
//
|
||||
result = u;
|
||||
for(int i = 0; i < result.data().used; ++i)
|
||||
{
|
||||
result.data().dp[i] = MP_MASK & ~(result.data().dp[i]);
|
||||
}
|
||||
//
|
||||
// We now need to pad out the left of the value with 1's to round up to a whole number of
|
||||
// CHAR_BIT * sizeof(mp_digit) units. Otherwise we'll end up with a very strange number of
|
||||
// bits set!
|
||||
//
|
||||
unsigned shift = result.data().used * DIGIT_BIT; // How many bits we're actually using
|
||||
// How many bits we actually need, reduced by one to account for a mythical sign bit:
|
||||
int padding = result.data().used * std::numeric_limits<mp_digit>::digits - shift - 1;
|
||||
while(padding >= std::numeric_limits<mp_digit>::digits)
|
||||
padding -= std::numeric_limits<mp_digit>::digits;
|
||||
|
||||
// Create a mask providing the extra bits we need and add to result:
|
||||
tommath_int mask;
|
||||
mask = static_cast<boost::long_long_type>((1u << padding) - 1);
|
||||
eval_left_shift(mask, shift);
|
||||
add(result, mask);
|
||||
}
|
||||
*/
|
||||
inline bool eval_is_zero(const tommath_int& val)
|
||||
{
|
||||
return mp_iszero(&val.data());
|
||||
}
|
||||
inline int eval_get_sign(const tommath_int& val)
|
||||
{
|
||||
return mp_iszero(&val.data()) ? 0 : SIGN(&val.data()) ? -1 : 1;
|
||||
}
|
||||
/*
|
||||
template <class A>
|
||||
inline void eval_convert_to(A* result, const tommath_int& val)
|
||||
{
|
||||
*result = boost::lexical_cast<A>(val.str(0, std::ios_base::fmtflags(0)));
|
||||
}
|
||||
inline void eval_convert_to(char* result, const tommath_int& val)
|
||||
{
|
||||
*result = static_cast<char>(boost::lexical_cast<int>(val.str(0, std::ios_base::fmtflags(0))));
|
||||
}
|
||||
inline void eval_convert_to(unsigned char* result, const tommath_int& val)
|
||||
{
|
||||
*result = static_cast<unsigned char>(boost::lexical_cast<unsigned>(val.str(0, std::ios_base::fmtflags(0))));
|
||||
}
|
||||
inline void eval_convert_to(signed char* result, const tommath_int& val)
|
||||
{
|
||||
*result = static_cast<signed char>(boost::lexical_cast<int>(val.str(0, std::ios_base::fmtflags(0))));
|
||||
}
|
||||
*/
|
||||
inline void eval_abs(tommath_int& result, const tommath_int& val)
|
||||
{
|
||||
detail::check_tommath_result(mp_abs(const_cast< ::mp_int*>(&val.data()), &result.data()));
|
||||
}
|
||||
inline void eval_gcd(tommath_int& result, const tommath_int& a, const tommath_int& b)
|
||||
{
|
||||
detail::check_tommath_result(mp_gcd(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
|
||||
}
|
||||
inline void eval_lcm(tommath_int& result, const tommath_int& a, const tommath_int& b)
|
||||
{
|
||||
detail::check_tommath_result(mp_lcm(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
|
||||
}
|
||||
inline void eval_powm(tommath_int& result, const tommath_int& base, const tommath_int& p, const tommath_int& m)
|
||||
{
|
||||
if(eval_get_sign(p) < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
||||
}
|
||||
detail::check_tommath_result(mp_exptmod(const_cast< ::mp_int*>(&base.data()), const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&m.data()), &result.data()));
|
||||
}
|
||||
|
||||
|
||||
inline void eval_qr(const tommath_int& x, const tommath_int& y,
|
||||
tommath_int& q, tommath_int& r)
|
||||
{
|
||||
detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&x.data()), const_cast< ::mp_int*>(&y.data()), &q.data(), &r.data()));
|
||||
}
|
||||
|
||||
inline unsigned eval_lsb(const tommath_int& val)
|
||||
{
|
||||
int c = eval_get_sign(val);
|
||||
if(c == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(c < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
return mp_cnt_lsb(const_cast< ::mp_int*>(&val.data()));
|
||||
}
|
||||
|
||||
inline unsigned eval_msb(const tommath_int& val)
|
||||
{
|
||||
int c = eval_get_sign(val);
|
||||
if(c == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(c < 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
return mp_count_bits(const_cast< ::mp_int*>(&val.data())) - 1;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
inline typename enable_if<is_unsigned<Integer>, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
|
||||
{
|
||||
static const mp_digit m = (static_cast<mp_digit>(1) << DIGIT_BIT) - 1;
|
||||
if(val <= m)
|
||||
{
|
||||
mp_digit d;
|
||||
detail::check_tommath_result(mp_mod_d(const_cast< ::mp_int*>(&x.data()), static_cast<mp_digit>(val), &d));
|
||||
return d;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default_ops::eval_integer_modulus(x, val);
|
||||
}
|
||||
}
|
||||
template <class Integer>
|
||||
inline typename enable_if<is_signed<Integer>, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
|
||||
{
|
||||
return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(const tommath_int& val)
|
||||
{
|
||||
std::size_t result = 0;
|
||||
std::size_t len = val.data().used;
|
||||
for(std::size_t i = 0; i < len; ++i)
|
||||
boost::hash_combine(result, val.data().dp[i]);
|
||||
boost::hash_combine(result, val.data().sign);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace backends
|
||||
|
||||
using boost::multiprecision::backends::tommath_int;
|
||||
|
||||
template<>
|
||||
struct number_category<tommath_int> : public mpl::int_<number_kind_integer>{};
|
||||
|
||||
typedef number<tommath_int > tom_int;
|
||||
typedef rational_adaptor<tommath_int> tommath_rational;
|
||||
typedef number<tommath_rational> tom_rational;
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace std{
|
||||
|
||||
template<boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
class numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >
|
||||
{
|
||||
typedef boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> number_type;
|
||||
public:
|
||||
BOOST_STATIC_CONSTEXPR bool is_specialized = true;
|
||||
//
|
||||
// Largest and smallest numbers are bounded only by available memory, set
|
||||
// to zero:
|
||||
//
|
||||
static number_type (min)()
|
||||
{
|
||||
return number_type();
|
||||
}
|
||||
static number_type (max)()
|
||||
{
|
||||
return number_type();
|
||||
}
|
||||
static number_type lowest() { return (min)(); }
|
||||
BOOST_STATIC_CONSTEXPR int digits = INT_MAX;
|
||||
BOOST_STATIC_CONSTEXPR int digits10 = (INT_MAX / 1000) * 301L;
|
||||
BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 3;
|
||||
BOOST_STATIC_CONSTEXPR bool is_signed = true;
|
||||
BOOST_STATIC_CONSTEXPR bool is_integer = true;
|
||||
BOOST_STATIC_CONSTEXPR bool is_exact = true;
|
||||
BOOST_STATIC_CONSTEXPR int radix = 2;
|
||||
static number_type epsilon() { return number_type(); }
|
||||
static number_type round_error() { return number_type(); }
|
||||
BOOST_STATIC_CONSTEXPR int min_exponent = 0;
|
||||
BOOST_STATIC_CONSTEXPR int min_exponent10 = 0;
|
||||
BOOST_STATIC_CONSTEXPR int max_exponent = 0;
|
||||
BOOST_STATIC_CONSTEXPR int max_exponent10 = 0;
|
||||
BOOST_STATIC_CONSTEXPR bool has_infinity = false;
|
||||
BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false;
|
||||
BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false;
|
||||
BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent;
|
||||
BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false;
|
||||
static number_type infinity() { return number_type(); }
|
||||
static number_type quiet_NaN() { return number_type(); }
|
||||
static number_type signaling_NaN() { return number_type(); }
|
||||
static number_type denorm_min() { return number_type(); }
|
||||
BOOST_STATIC_CONSTEXPR bool is_iec559 = false;
|
||||
BOOST_STATIC_CONSTEXPR bool is_bounded = false;
|
||||
BOOST_STATIC_CONSTEXPR bool is_modulo = false;
|
||||
BOOST_STATIC_CONSTEXPR bool traps = false;
|
||||
BOOST_STATIC_CONSTEXPR bool tinyness_before = false;
|
||||
BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero;
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits10;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_digits10;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_signed;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_integer;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_exact;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::radix;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent10;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent10;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_infinity;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_quiet_NaN;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_signaling_NaN;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm_loss;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_iec559;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_bounded;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_modulo;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::traps;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::tinyness_before;
|
||||
template <boost::multiprecision::expression_template_option ExpressionTemplates>
|
||||
BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::round_style;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright Vicente J. Botet Escriba 2009-2011
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MP_EXPLICIT_CONVERTIBLE_HPP
|
||||
#define BOOST_MP_EXPLICIT_CONVERTIBLE_HPP
|
||||
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/utility/declval.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
namespace detail {
|
||||
|
||||
template <int N>
|
||||
struct dummy_size {};
|
||||
|
||||
template<typename S, typename T>
|
||||
struct has_generic_interconversion
|
||||
{
|
||||
typedef typename mpl::if_c <
|
||||
is_number<S>::value && is_number<T>::value,
|
||||
typename mpl::if_c <
|
||||
number_category<S>::value == number_kind_integer,
|
||||
typename mpl::if_c<
|
||||
number_category<T>::value == number_kind_integer
|
||||
|| number_category<T>::value == number_kind_floating_point
|
||||
|| number_category<T>::value == number_kind_rational
|
||||
|| number_category<T>::value == number_kind_fixed_point,
|
||||
mpl::true_,
|
||||
mpl::false_
|
||||
>::type,
|
||||
typename mpl::if_c<
|
||||
number_category<S>::value == number_kind_rational,
|
||||
typename mpl::if_c<
|
||||
number_category<T>::value == number_kind_rational
|
||||
|| number_category<T>::value == number_kind_rational,
|
||||
mpl::true_,
|
||||
mpl::false_
|
||||
>::type,
|
||||
typename mpl::if_c<
|
||||
number_category<T>::value == number_kind_floating_point,
|
||||
mpl::true_,
|
||||
mpl::false_
|
||||
>::type
|
||||
>::type
|
||||
> ::type,
|
||||
mpl::false_
|
||||
> ::type type;
|
||||
};
|
||||
|
||||
template<typename S, typename T>
|
||||
struct is_explicitly_convertible_imp
|
||||
{
|
||||
#ifndef BOOST_NO_SFINAE_EXPR
|
||||
template<typename S1, typename T1>
|
||||
static type_traits::yes_type selector(dummy_size<sizeof(static_cast<T1>(declval<S1>()))>*);
|
||||
|
||||
template<typename S1, typename T1>
|
||||
static type_traits::no_type selector(...);
|
||||
|
||||
static const bool value = sizeof(selector<S, T>(0)) == sizeof(type_traits::yes_type);
|
||||
|
||||
typedef boost::integral_constant<bool, value> type;
|
||||
#else
|
||||
typedef typename has_generic_interconversion<S, T>::type gen_type;
|
||||
typedef mpl::bool_<boost::is_convertible<S, T>::value || gen_type::value> type;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_explicitly_convertible : public is_explicitly_convertible_imp<From, To>::type
|
||||
{
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_SFINAE_EXPR
|
||||
template<class Backend1, expression_template_option ExpressionTemplates1, class Backend2, expression_template_option ExpressionTemplates2>
|
||||
struct is_explicitly_convertible<number<Backend1, ExpressionTemplates1>, number<Backend2, ExpressionTemplates2> >
|
||||
: public is_explicitly_convertible<Backend1, Backend2>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MATH_EXTRACT_EXPONENT_HPP
|
||||
#define BOOST_MATH_EXTRACT_EXPONENT_HPP
|
||||
|
||||
#include <boost/multiprecision/number.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace multiprecision{
|
||||
namespace backends{
|
||||
|
||||
template <class Backend, int cat>
|
||||
struct extract_exponent_type
|
||||
{
|
||||
typedef int type;
|
||||
};
|
||||
template <class Backend>
|
||||
struct extract_exponent_type<Backend, number_kind_floating_point>
|
||||
{
|
||||
typedef typename Backend::exponent_type type;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2015 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MP_IS_BACKEND_HPP
|
||||
#define BOOST_MP_IS_BACKEND_HPP
|
||||
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/multiprecision/detail/number_base.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(signed_types)
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(unsigned_types)
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(float_types)
|
||||
|
||||
template <class T>
|
||||
struct is_backend
|
||||
{
|
||||
static const bool value = has_signed_types<T>::value && has_unsigned_types<T>::value && has_float_types<T>::value;
|
||||
};
|
||||
|
||||
template <class Backend>
|
||||
struct other_backend
|
||||
{
|
||||
typedef typename boost::conditional<
|
||||
boost::is_same<number<Backend>, number<Backend, et_on> >::value,
|
||||
number<Backend, et_off>, number<Backend, et_on> >::type type;
|
||||
};
|
||||
|
||||
template <class B, class V>
|
||||
struct number_from_backend
|
||||
{
|
||||
typedef typename boost::conditional <
|
||||
boost::is_convertible<V, number<B> >::value,
|
||||
number<B>,
|
||||
typename other_backend<B>::type > ::type type;
|
||||
};
|
||||
|
||||
template <bool b, class T, class U>
|
||||
struct is_first_backend_imp{ static const bool value = false; };
|
||||
template <class T, class U>
|
||||
struct is_first_backend_imp<true, T, U>{ static const bool value = is_convertible<U, number<T, et_on> >::value || is_convertible<U, number<T, et_off> >::value; };
|
||||
|
||||
template <class T, class U>
|
||||
struct is_first_backend : is_first_backend_imp<is_backend<T>::value, T, U> {};
|
||||
|
||||
template <bool b, class T, class U>
|
||||
struct is_second_backend_imp{ static const bool value = false; };
|
||||
template <class T, class U>
|
||||
struct is_second_backend_imp<true, T, U>{ static const bool value = (is_convertible<T, number<U, et_on> >::value || is_convertible<T, number<U, et_off> >::value) && !is_first_backend<T, U>::value; };
|
||||
|
||||
template <class T, class U>
|
||||
struct is_second_backend : is_second_backend_imp<is_backend<U>::value, T, U> {};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_MP_IS_BACKEND_HPP
|
||||
@@ -0,0 +1,33 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2015 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_IS_BYTE_CONTAINER_HPP
|
||||
#define BOOST_IS_BYTE_CONTAINER_HPP
|
||||
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_member_value_type, value_type, false)
|
||||
BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_member_const_iterator, const_iterator, false)
|
||||
|
||||
template <class C, bool b>
|
||||
struct is_byte_container_imp
|
||||
{
|
||||
static const bool value = boost::is_integral<typename C::value_type>::value && (sizeof(typename C::value_type) == 1);
|
||||
};
|
||||
|
||||
template <class C>
|
||||
struct is_byte_container_imp<C, false> : public boost::false_type {};
|
||||
|
||||
template <class C>
|
||||
struct is_byte_container : public is_byte_container_imp<C, has_member_value_type<C>::value && has_member_const_iterator<C>::value> {};
|
||||
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_IS_BYTE_CONTAINER_HPP
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright Vicente J. Botet Escriba 2009-2011
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MP_RESTRICTED_CONVERSION_HPP
|
||||
#define BOOST_MP_RESTRICTED_CONVERSION_HPP
|
||||
|
||||
#include <boost/multiprecision/traits/explicit_conversion.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/multiprecision/detail/number_base.hpp>
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace detail{
|
||||
|
||||
|
||||
template <class From, class To>
|
||||
struct is_lossy_conversion
|
||||
{
|
||||
typedef typename mpl::if_c<
|
||||
((number_category<From>::value == number_kind_floating_point) && (number_category<To>::value == number_kind_integer))
|
||||
/* || ((number_category<From>::value == number_kind_floating_point) && (number_category<To>::value == number_kind_rational))*/
|
||||
|| ((number_category<From>::value == number_kind_rational) && (number_category<To>::value == number_kind_integer))
|
||||
|| ((number_category<From>::value == number_kind_fixed_point) && (number_category<To>::value == number_kind_integer))
|
||||
|| (number_category<From>::value == number_kind_unknown)
|
||||
|| (number_category<To>::value == number_kind_unknown),
|
||||
mpl::true_,
|
||||
mpl::false_
|
||||
>::type type;
|
||||
static const bool value = type::value;
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_restricted_conversion
|
||||
{
|
||||
typedef typename mpl::if_c<
|
||||
((is_explicitly_convertible<From, To>::value && !is_convertible<From, To>::value)
|
||||
|| is_lossy_conversion<From, To>::value),
|
||||
mpl::true_,
|
||||
mpl::false_
|
||||
>::type type;
|
||||
static const bool value = type::value;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MP_RESTRICTED_CONVERSION_HPP
|
||||
|
||||
Reference in New Issue
Block a user