stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
+236
@@ -0,0 +1,236 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 = (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 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 = (int)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 = (int)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 = (int)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 = (int)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
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
}
|
||||
BOOST_ASSERT(t.compare(default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >()) < 0);
|
||||
|
||||
Exponent k, nn;
|
||||
eval_convert_to(&nn, n);
|
||||
k = nn ? Exponent(1) << (msb(nn) / 2) : 0;
|
||||
eval_ldexp(t, t, -k);
|
||||
|
||||
eval_exp_taylor(res, t);
|
||||
//
|
||||
// Square 1 + res k times:
|
||||
//
|
||||
for(int 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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,550 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_ADD_HPP
|
||||
#define BOOST_MP_CPP_INT_ADD_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
//
|
||||
// This is the key addition routine where all the argument types are non-trivial cpp_int's:
|
||||
//
|
||||
template <class CppInt1, class CppInt2, class CppInt3>
|
||||
inline void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
// Nothing fancy, just let uintmax_t take the strain:
|
||||
double_limb_type carry = 0;
|
||||
unsigned m, x;
|
||||
unsigned as = a.size();
|
||||
unsigned bs = b.size();
|
||||
minmax(as, bs, m, x);
|
||||
if(x == 1)
|
||||
{
|
||||
bool s = a.sign();
|
||||
result = static_cast<double_limb_type>(*a.limbs()) + static_cast<double_limb_type>(*b.limbs());
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
result.resize(x, x);
|
||||
typename CppInt2::const_limb_pointer pa = a.limbs();
|
||||
typename CppInt3::const_limb_pointer pb = b.limbs();
|
||||
typename CppInt1::limb_pointer pr = result.limbs();
|
||||
typename CppInt1::limb_pointer pr_end = pr + m;
|
||||
|
||||
if(as < bs)
|
||||
swap(pa, pb);
|
||||
|
||||
// First where a and b overlap:
|
||||
while(pr != pr_end)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
*pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
*pr = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= CppInt1::limb_bits;
|
||||
++pr, ++pa, ++pb;
|
||||
}
|
||||
pr_end += x - m;
|
||||
// Now where only a has digits:
|
||||
while(pr != pr_end)
|
||||
{
|
||||
if(!carry)
|
||||
{
|
||||
if(pa != pr)
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
|
||||
std::copy(pa, pa + (pr_end - pr), stdext::checked_array_iterator<limb_type*>(pr, result.size()));
|
||||
#else
|
||||
std::copy(pa, pa + (pr_end - pr), pr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
carry += static_cast<double_limb_type>(*pa);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
*pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
*pr = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= CppInt1::limb_bits;
|
||||
++pr, ++pa;
|
||||
}
|
||||
if(carry)
|
||||
{
|
||||
// We overflowed, need to add one more limb:
|
||||
result.resize(x + 1, x + 1);
|
||||
if(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];
|
||||
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,252 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2015 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
|
||||
#ifndef BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
#define BOOST_MP_CPP_INT_IMPORT_EXPORT_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace multiprecision {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Backend, class Unsigned>
|
||||
void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::false_& tag)
|
||||
{
|
||||
unsigned limb = bit_location / (sizeof(limb_type) * CHAR_BIT);
|
||||
unsigned shift = bit_location % (sizeof(limb_type) * CHAR_BIT);
|
||||
|
||||
limb_type mask = chunk_bits >= sizeof(limb_type) * CHAR_BIT ? ~static_cast<limb_type>(0u) : (static_cast<limb_type>(1u) << chunk_bits) - 1;
|
||||
|
||||
limb_type value = static_cast<limb_type>(bits & mask) << shift;
|
||||
if(value)
|
||||
{
|
||||
if(val.size() == limb)
|
||||
{
|
||||
val.resize(limb + 1, limb + 1);
|
||||
if(val.size() > limb)
|
||||
val.limbs()[limb] = value;
|
||||
}
|
||||
else if(val.size() > limb)
|
||||
val.limbs()[limb] |= value;
|
||||
}
|
||||
if(chunk_bits > sizeof(limb_type) * CHAR_BIT - shift)
|
||||
{
|
||||
shift = sizeof(limb_type) * CHAR_BIT - shift;
|
||||
chunk_bits -= shift;
|
||||
bit_location += shift;
|
||||
bits >>= shift;
|
||||
if(bits)
|
||||
assign_bits(val, bits, bit_location, chunk_bits, tag);
|
||||
}
|
||||
}
|
||||
template <class Backend, class Unsigned>
|
||||
void assign_bits(Backend& val, Unsigned bits, unsigned bit_location, unsigned chunk_bits, const mpl::true_&)
|
||||
{
|
||||
typedef typename Backend::local_limb_type local_limb_type;
|
||||
//
|
||||
// Check for possible overflow, this may trigger an exception, or have no effect
|
||||
// depending on whether this is a checked integer or not:
|
||||
//
|
||||
if((bit_location >= sizeof(local_limb_type) * CHAR_BIT) && bits)
|
||||
val.resize(2, 2);
|
||||
else
|
||||
{
|
||||
local_limb_type mask = chunk_bits >= sizeof(local_limb_type) * CHAR_BIT ? ~static_cast<local_limb_type>(0u) : (static_cast<local_limb_type>(1u) << chunk_bits) - 1;
|
||||
local_limb_type value = (static_cast<local_limb_type>(bits) & mask) << bit_location;
|
||||
*val.limbs() |= value;
|
||||
//
|
||||
// Check for overflow bits:
|
||||
//
|
||||
bit_location = sizeof(local_limb_type) * CHAR_BIT - bit_location;
|
||||
bits >>= bit_location;
|
||||
if(bits)
|
||||
val.resize(2, 2); // May throw!
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned bits, const mpl::false_&)
|
||||
{
|
||||
unsigned limb_count = static_cast<unsigned>(bits / (sizeof(limb_type) * CHAR_BIT));
|
||||
if(bits % (sizeof(limb_type) * CHAR_BIT))
|
||||
++limb_count;
|
||||
static const unsigned max_limbs = MaxBits ? MaxBits / (CHAR_BIT * sizeof(limb_type)) + ((MaxBits % (CHAR_BIT * sizeof(limb_type))) ? 1 : 0) : (std::numeric_limits<unsigned>::max)();
|
||||
if(limb_count > max_limbs)
|
||||
limb_count = max_limbs;
|
||||
newval.resize(limb_count, limb_count);
|
||||
std::memset(newval.limbs(), 0, newval.size() * sizeof(limb_type));
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator>
|
||||
inline void resize_to_bit_size(cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& newval, unsigned, const mpl::true_&)
|
||||
{
|
||||
*newval.limbs() = 0;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
||||
import_bits_generic(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
typename number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>::backend_type newval;
|
||||
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
typedef typename boost::make_unsigned<value_type>::type unsigned_value_type;
|
||||
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
|
||||
typedef typename boost::make_unsigned<difference_type>::type size_type;
|
||||
typedef typename cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>::trivial_tag tag_type;
|
||||
|
||||
if(!chunk_size)
|
||||
chunk_size = std::numeric_limits<value_type>::digits;
|
||||
|
||||
size_type limbs = std::distance(i, j);
|
||||
size_type bits = limbs * chunk_size;
|
||||
|
||||
detail::resize_to_bit_size(newval, static_cast<unsigned>(bits), tag_type());
|
||||
|
||||
difference_type bit_location = msv_first ? bits - chunk_size : 0;
|
||||
difference_type bit_location_change = msv_first ? -static_cast<difference_type>(chunk_size) : chunk_size;
|
||||
|
||||
while(i != j)
|
||||
{
|
||||
detail::assign_bits(newval, static_cast<unsigned_value_type>(*i), static_cast<unsigned>(bit_location), chunk_size, tag_type());
|
||||
++i;
|
||||
bit_location += bit_location_change;
|
||||
}
|
||||
|
||||
newval.normalize();
|
||||
|
||||
val.backend().swap(newval);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline typename boost::disable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type
|
||||
import_bits_fast(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
|
||||
{
|
||||
std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
|
||||
std::size_t limb_len = byte_len / sizeof(limb_type);
|
||||
if(byte_len % sizeof(limb_type))
|
||||
++limb_len;
|
||||
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
|
||||
result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data!
|
||||
result.limbs()[result.size() - 1] = 0u;
|
||||
std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(limb_type)));
|
||||
result.normalize(); // In case data has leading zeros.
|
||||
return val;
|
||||
}
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline typename boost::enable_if_c<boost::multiprecision::backends::is_trivial_cpp_int<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator> >::value, number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&>::type
|
||||
import_bits_fast(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0)
|
||||
{
|
||||
cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>& result = val.backend();
|
||||
std::size_t byte_len = (j - i) * (chunk_size ? chunk_size / CHAR_BIT : sizeof(*i));
|
||||
std::size_t limb_len = byte_len / sizeof(result.limbs()[0]);
|
||||
if(byte_len % sizeof(result.limbs()[0]))
|
||||
++limb_len;
|
||||
result.limbs()[0] = 0u;
|
||||
result.resize(static_cast<unsigned>(limb_len), static_cast<unsigned>(limb_len)); // checked types may throw here if they're not large enough to hold the data!
|
||||
std::memcpy(result.limbs(), i, (std::min)(byte_len, result.size() * sizeof(result.limbs()[0])));
|
||||
result.normalize(); // In case data has leading zeros.
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class Iterator>
|
||||
inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
||||
import_bits(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, Iterator i, Iterator j, unsigned chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
|
||||
}
|
||||
|
||||
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator, expression_template_option ExpressionTemplates, class T>
|
||||
inline number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
||||
import_bits(
|
||||
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val, T* i, T* j, unsigned chunk_size = 0, bool msv_first = true)
|
||||
{
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
if(((chunk_size % CHAR_BIT) == 0) && !msv_first)
|
||||
return detail::import_bits_fast(val, i, j, chunk_size);
|
||||
#endif
|
||||
return detail::import_bits_generic(val, i, j, chunk_size, msv_first);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Backend>
|
||||
boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::false_& tag)
|
||||
{
|
||||
unsigned limb = location / (sizeof(limb_type) * CHAR_BIT);
|
||||
unsigned shift = location % (sizeof(limb_type) * CHAR_BIT);
|
||||
boost::uintmax_t result = 0;
|
||||
boost::uintmax_t mask = count == std::numeric_limits<boost::uintmax_t>::digits ? ~static_cast<boost::uintmax_t>(0) : (static_cast<boost::uintmax_t>(1u) << count) - 1;
|
||||
if(count > (sizeof(limb_type) * CHAR_BIT - shift))
|
||||
{
|
||||
result = extract_bits(val, location + sizeof(limb_type) * CHAR_BIT - shift, count - sizeof(limb_type) * CHAR_BIT + shift, tag);
|
||||
result <<= sizeof(limb_type) * CHAR_BIT - shift;
|
||||
}
|
||||
if(limb < val.size())
|
||||
result |= (val.limbs()[limb] >> shift) & mask;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Backend>
|
||||
inline boost::uintmax_t extract_bits(const Backend& val, unsigned location, unsigned count, const mpl::true_&)
|
||||
{
|
||||
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,656 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_MISC_HPP
|
||||
#define BOOST_MP_CPP_INT_MISC_HPP
|
||||
|
||||
#include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
|
||||
#include <boost/integer/common_factor_rt.hpp> // gcd/lcm
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4702)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
template <class R, class CppInt>
|
||||
void check_in_range(const CppInt& val, const mpl::int_<checked>&)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<R, CppInt>::type cast_type;
|
||||
if(val.sign())
|
||||
{
|
||||
if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::min)())) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::max)())) > 0)
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
|
||||
}
|
||||
}
|
||||
template <class R, class CppInt>
|
||||
inline void check_in_range(const CppInt& /*val*/, const mpl::int_<unchecked>&) BOOST_NOEXCEPT {}
|
||||
|
||||
inline void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {}
|
||||
inline void check_is_negative(const mpl::false_&)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
inline Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT
|
||||
{
|
||||
return -i;
|
||||
}
|
||||
template <class Integer>
|
||||
inline Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT
|
||||
{
|
||||
return ~(i-1);
|
||||
}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
typedef mpl::int_<Checked1> checked_type;
|
||||
check_in_range<R>(backend, checked_type());
|
||||
|
||||
*result = static_cast<R>(backend.limbs()[0]);
|
||||
unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
for(unsigned i = 1; (i < backend.size()) && (shift < static_cast<unsigned>(std::numeric_limits<R>::digits)); ++i)
|
||||
{
|
||||
*result += static_cast<R>(backend.limbs()[i]) << shift;
|
||||
shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
}
|
||||
if(backend.sign())
|
||||
{
|
||||
check_is_negative(boost::is_signed<R>());
|
||||
*result = negate_integer(*result, boost::is_signed<R>());
|
||||
}
|
||||
}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_floating_point<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_MP_NOEXCEPT_IF(is_arithmetic<R>::value)
|
||||
{
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
|
||||
unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
*result = static_cast<R>(*p);
|
||||
for(unsigned i = 1; i < backend.size(); ++i)
|
||||
{
|
||||
*result += static_cast<R>(std::ldexp(static_cast<long double>(p[i]), shift));
|
||||
shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
}
|
||||
if(backend.sign())
|
||||
*result = -*result;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
|
||||
eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
return (val.size() == 1) && (val.limbs()[0] == 0);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
|
||||
eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
result = val;
|
||||
result.sign(false);
|
||||
}
|
||||
|
||||
//
|
||||
// Get the location of the least-significant-bit:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
|
||||
//
|
||||
// Find the index of the least significant limb that is non-zero:
|
||||
//
|
||||
unsigned index = 0;
|
||||
while(!a.limbs()[index] && (index < a.size()))
|
||||
++index;
|
||||
//
|
||||
// Find the index of the least significant bit within that limb:
|
||||
//
|
||||
unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
|
||||
|
||||
return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the location of the most-significant-bit:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
//
|
||||
// Find the index of the most significant bit that is non-zero:
|
||||
//
|
||||
return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
return eval_msb_imp(a);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
|
||||
eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
return false;
|
||||
return val.limbs()[offset] & mask ? true : false;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
{
|
||||
unsigned os = val.size();
|
||||
val.resize(offset + 1, offset + 1);
|
||||
if(offset >= val.size())
|
||||
return; // fixed precision overflow
|
||||
for(unsigned i = os; i <= offset; ++i)
|
||||
val.limbs()[i] = 0;
|
||||
}
|
||||
val.limbs()[offset] |= mask;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
return;
|
||||
val.limbs()[offset] &= ~mask;
|
||||
val.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
|
||||
{
|
||||
unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
||||
if(offset >= val.size())
|
||||
{
|
||||
unsigned os = val.size();
|
||||
val.resize(offset + 1, offset + 1);
|
||||
if(offset >= val.size())
|
||||
return; // fixed precision overflow
|
||||
for(unsigned i = os; i <= offset; ++i)
|
||||
val.limbs()[i] = 0;
|
||||
}
|
||||
val.limbs()[offset] ^= mask;
|
||||
val.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_qr(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
divide_unsigned_helper(&q, x, y, r);
|
||||
q.sign(x.sign() != y.sign());
|
||||
r.sign(x.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_qr(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
||||
limb_type y,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
divide_unsigned_helper(&q, x, y, r);
|
||||
q.sign(x.sign());
|
||||
r.sign(x.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
|
||||
inline typename enable_if_c<is_integral<U>::value>::type eval_qr(
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
||||
U y,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
using default_ops::eval_qr;
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
|
||||
t = y;
|
||||
eval_qr(x, t, q, r);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
inline typename enable_if_c<is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
|
||||
eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
|
||||
{
|
||||
if((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits<limb_type>::max)()))
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> d;
|
||||
divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>*>(0), x, static_cast<limb_type>(val), d);
|
||||
return d.limbs()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return default_ops::eval_integer_modulus(x, val);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
|
||||
eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
|
||||
{
|
||||
return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
|
||||
}
|
||||
|
||||
inline limb_type integer_gcd_reduce(limb_type u, limb_type v)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(u > v)
|
||||
std::swap(u, v);
|
||||
if(u == v)
|
||||
break;
|
||||
v -= u;
|
||||
v >>= boost::multiprecision::detail::find_lsb(v);
|
||||
} while(true);
|
||||
return u;
|
||||
}
|
||||
|
||||
inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(u > v)
|
||||
std::swap(u, v);
|
||||
if(u == v)
|
||||
break;
|
||||
if(v <= ~static_cast<limb_type>(0))
|
||||
{
|
||||
u = integer_gcd_reduce(static_cast<limb_type>(v), static_cast<limb_type>(u));
|
||||
break;
|
||||
}
|
||||
v -= u;
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
while((v & 1u) == 0)
|
||||
#else
|
||||
while((static_cast<unsigned>(v) & 1u) == 0)
|
||||
#endif
|
||||
v >>= 1;
|
||||
} while(true);
|
||||
return u;
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
limb_type v)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
int shift;
|
||||
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a);
|
||||
|
||||
int s = eval_get_sign(u);
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if(s < 0)
|
||||
{
|
||||
u.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
if(v == 0)
|
||||
{
|
||||
result = u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
|
||||
unsigned us = eval_lsb(u);
|
||||
unsigned vs = boost::multiprecision::detail::find_lsb(v);
|
||||
shift = (std::min)(us, vs);
|
||||
eval_right_shift(u, us);
|
||||
if(vs)
|
||||
v >>= vs;
|
||||
|
||||
do
|
||||
{
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
if(u.size() <= 2)
|
||||
{
|
||||
if(u.size() == 1)
|
||||
v = integer_gcd_reduce(*u.limbs(), v);
|
||||
else
|
||||
{
|
||||
double_limb_type i;
|
||||
i = u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
||||
v = static_cast<limb_type>(integer_gcd_reduce(i, static_cast<double_limb_type>(v)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
eval_subtract(u, v);
|
||||
us = eval_lsb(u);
|
||||
eval_right_shift(u, us);
|
||||
}
|
||||
while(true);
|
||||
|
||||
result = v;
|
||||
eval_left_shift(result, shift);
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
inline typename enable_if_c<is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const Integer& v)
|
||||
{
|
||||
eval_gcd(result, a, static_cast<limb_type>(v));
|
||||
}
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
||||
inline typename enable_if_c<is_signed<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const Integer& v)
|
||||
{
|
||||
eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b)
|
||||
{
|
||||
using default_ops::eval_lsb;
|
||||
using default_ops::eval_is_zero;
|
||||
using default_ops::eval_get_sign;
|
||||
|
||||
if(a.size() == 1)
|
||||
{
|
||||
eval_gcd(result, b, *a.limbs());
|
||||
return;
|
||||
}
|
||||
if(b.size() == 1)
|
||||
{
|
||||
eval_gcd(result, a, *b.limbs());
|
||||
return;
|
||||
}
|
||||
|
||||
int shift;
|
||||
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a), v(b);
|
||||
|
||||
int s = eval_get_sign(u);
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if(s < 0)
|
||||
{
|
||||
u.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
s = eval_get_sign(v);
|
||||
if(s < 0)
|
||||
{
|
||||
v.negate();
|
||||
}
|
||||
else if(s == 0)
|
||||
{
|
||||
result = u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
|
||||
unsigned us = eval_lsb(u);
|
||||
unsigned vs = eval_lsb(v);
|
||||
shift = (std::min)(us, vs);
|
||||
eval_right_shift(u, us);
|
||||
eval_right_shift(v, vs);
|
||||
|
||||
do
|
||||
{
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
s = u.compare(v);
|
||||
if(s > 0)
|
||||
u.swap(v);
|
||||
if(s == 0)
|
||||
break;
|
||||
if(v.size() <= 2)
|
||||
{
|
||||
if(v.size() == 1)
|
||||
u = integer_gcd_reduce(*v.limbs(), *u.limbs());
|
||||
else
|
||||
{
|
||||
double_limb_type i, j;
|
||||
i = v.limbs()[0] | (static_cast<double_limb_type>(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
||||
j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
||||
u = integer_gcd_reduce(i, j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
eval_subtract(v, u);
|
||||
vs = eval_lsb(v);
|
||||
eval_right_shift(v, vs);
|
||||
}
|
||||
while(true);
|
||||
|
||||
result = u;
|
||||
eval_left_shift(result, shift);
|
||||
}
|
||||
//
|
||||
// Now again for trivial backends:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_gcd(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT
|
||||
{
|
||||
*result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs());
|
||||
}
|
||||
// This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version:
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
|
||||
eval_lcm(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs());
|
||||
result.normalize(); // result may overflow the specified number of bits
|
||||
}
|
||||
|
||||
inline void conversion_overflow(const mpl::int_<checked>&)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
|
||||
}
|
||||
inline void conversion_overflow(const mpl::int_<unchecked>&){}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value
|
||||
>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
|
||||
{
|
||||
typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
|
||||
if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
|
||||
{
|
||||
if(val.isneg())
|
||||
{
|
||||
if(static_cast<common_type>(*val.limbs()) > -static_cast<common_type>((std::numeric_limits<R>::min)()))
|
||||
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result = (std::numeric_limits<R>::min)();
|
||||
}
|
||||
else
|
||||
{
|
||||
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result = (std::numeric_limits<R>::max)();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = static_cast<R>(*val.limbs());
|
||||
if(val.isneg())
|
||||
{
|
||||
check_is_negative(mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>());
|
||||
*result = negate_integer(*result, mpl::bool_<is_signed_number<R>::value || (number_category<R>::value == number_kind_floating_point)>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& boost::is_convertible<typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type, R>::value
|
||||
>::type
|
||||
eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
|
||||
{
|
||||
typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
|
||||
if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
|
||||
{
|
||||
conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
*result = (std::numeric_limits<R>::max)();
|
||||
}
|
||||
else
|
||||
*result = static_cast<R>(*val.limbs());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
//
|
||||
// Find the index of the least significant bit within that limb:
|
||||
//
|
||||
return boost::multiprecision::detail::find_lsb(*a.limbs());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb_imp(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
//
|
||||
// Find the index of the least significant bit within that limb:
|
||||
//
|
||||
return boost::multiprecision::detail::find_msb(*a.limbs());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
||||
eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
||||
{
|
||||
using default_ops::eval_get_sign;
|
||||
if(eval_get_sign(a) == 0)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
||||
}
|
||||
if(a.sign())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
||||
}
|
||||
return eval_msb_imp(a);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline std::size_t hash_value(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t result = 0;
|
||||
for(unsigned i = 0; i < val.size(); ++i)
|
||||
{
|
||||
boost::hash_combine(result, val.limbs()[i]);
|
||||
}
|
||||
boost::hash_combine(result, val.sign());
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,490 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
||||
//
|
||||
// Comparison operators for cpp_int_backend:
|
||||
//
|
||||
#ifndef BOOST_MP_CPP_INT_MUL_HPP
|
||||
#define BOOST_MP_CPP_INT_MUL_HPP
|
||||
|
||||
namespace boost{ namespace multiprecision{ namespace backends{
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(!val)
|
||||
{
|
||||
result = static_cast<limb_type>(0);
|
||||
return;
|
||||
}
|
||||
if((void*)&a != (void*)&result)
|
||||
result.resize(a.size(), a.size());
|
||||
double_limb_type carry = 0;
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer p = result.limbs();
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pe = result.limbs() + result.size();
|
||||
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
|
||||
while(p != pe)
|
||||
{
|
||||
carry += static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(val);
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
*p = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
*p = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
++p, ++pa;
|
||||
}
|
||||
if(carry)
|
||||
{
|
||||
unsigned i = result.size();
|
||||
result.resize(i + 1, i + 1);
|
||||
if(result.size() > i)
|
||||
result.limbs()[i] = static_cast<limb_type>(carry);
|
||||
}
|
||||
result.sign(a.sign());
|
||||
if(!cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable)
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
//
|
||||
// resize_for_carry forces a resize of the underlying buffer only if a previous request
|
||||
// for "required" elements could possibly have failed, *and* we have checking enabled.
|
||||
// This will cause an overflow error inside resize():
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& /*result*/, unsigned /*required*/){}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
inline void resize_for_carry(cpp_int_backend<MinBits1, MaxBits1, SignType1, checked, void>& result, unsigned required)
|
||||
{
|
||||
if(result.size() != required)
|
||||
result.resize(required, required);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
// Very simple long multiplication, only usable for small numbers of limb_type's
|
||||
// but that's the typical use case for this type anyway:
|
||||
//
|
||||
// Special cases first:
|
||||
//
|
||||
unsigned as = a.size();
|
||||
unsigned bs = b.size();
|
||||
typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::const_limb_pointer pa = a.limbs();
|
||||
typename cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>::const_limb_pointer pb = b.limbs();
|
||||
if(as == 1)
|
||||
{
|
||||
bool s = b.sign() != a.sign();
|
||||
if(bs == 1)
|
||||
{
|
||||
result = static_cast<double_limb_type>(*pa) * static_cast<double_limb_type>(*pb);
|
||||
}
|
||||
else
|
||||
{
|
||||
limb_type l = *pa;
|
||||
eval_multiply(result, b, l);
|
||||
}
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
if(bs == 1)
|
||||
{
|
||||
bool s = b.sign() != a.sign();
|
||||
limb_type l = *pb;
|
||||
eval_multiply(result, a, l);
|
||||
result.sign(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if((void*)&result == (void*)&a)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(a);
|
||||
eval_multiply(result, t, b);
|
||||
return;
|
||||
}
|
||||
if((void*)&result == (void*)&b)
|
||||
{
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(b);
|
||||
eval_multiply(result, a, t);
|
||||
return;
|
||||
}
|
||||
|
||||
result.resize(as + bs, as + bs - 1);
|
||||
typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
|
||||
|
||||
static const double_limb_type limb_max = ~static_cast<limb_type>(0u);
|
||||
static const double_limb_type double_limb_max = ~static_cast<double_limb_type>(0u);
|
||||
BOOST_STATIC_ASSERT(double_limb_max - 2 * limb_max >= limb_max * limb_max);
|
||||
|
||||
double_limb_type carry = 0;
|
||||
std::memset(pr, 0, result.size() * sizeof(limb_type));
|
||||
for(unsigned i = 0; i < as; ++i)
|
||||
{
|
||||
unsigned inner_limit = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::variable ? bs : (std::min)(result.size() - i, bs);
|
||||
for(unsigned j = 0; j < inner_limit; ++j)
|
||||
{
|
||||
BOOST_ASSERT(i+j < result.size());
|
||||
#if (!defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || !BOOST_WORKAROUND(BOOST_GCC_VERSION, <= 50100)
|
||||
BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized
|
||||
|| ((std::numeric_limits<double_limb_type>::max)() - carry
|
||||
>
|
||||
static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value) * static_cast<double_limb_type>(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value)));
|
||||
#endif
|
||||
carry += static_cast<double_limb_type>(pa[i]) * static_cast<double_limb_type>(pb[j]);
|
||||
BOOST_ASSERT(!std::numeric_limits<double_limb_type>::is_specialized || ((std::numeric_limits<double_limb_type>::max)() - carry >= pr[i+j]));
|
||||
carry += pr[i + j];
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[i + j] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
#else
|
||||
pr[i + j] = static_cast<limb_type>(carry);
|
||||
#endif
|
||||
carry >>= cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
||||
BOOST_ASSERT(carry <= (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value));
|
||||
}
|
||||
resize_for_carry(result, as + bs); // May throw if checking is enabled
|
||||
if(i + bs < result.size())
|
||||
pr[i + bs] = static_cast<limb_type>(carry);
|
||||
carry = 0;
|
||||
}
|
||||
result.normalize();
|
||||
//
|
||||
// Set the sign of the result:
|
||||
//
|
||||
result.sign(a.sign() != b.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, a);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(val <= (std::numeric_limits<limb_type>::max)())
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
|
||||
#else
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
|
||||
t = val;
|
||||
#endif
|
||||
eval_multiply(result, a, t);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(val > 0)
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
else
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
|
||||
result.negate();
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value >::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
|
||||
const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
if(val > 0)
|
||||
{
|
||||
if(val <= (std::numeric_limits<limb_type>::max)())
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(val));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(val >= -static_cast<signed_double_limb_type>((std::numeric_limits<limb_type>::max)()))
|
||||
{
|
||||
eval_multiply(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(val)));
|
||||
result.negate();
|
||||
return;
|
||||
}
|
||||
#if defined(BOOST_LITTLE_ENDIAN) && !defined(BOOST_MP_TEST_NO_LE)
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(val);
|
||||
#else
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t;
|
||||
t = val;
|
||||
#endif
|
||||
eval_multiply(result, a, t);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
||||
eval_multiply(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const signed_double_limb_type& val) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
eval_multiply(result, result, val);
|
||||
}
|
||||
|
||||
//
|
||||
// Now over again for trivial cpp_int's:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.sign(result.sign() != o.sign());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
|| is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.sign(a.sign() != b.sign());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
||||
const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
||||
{
|
||||
*result.limbs() = detail::checked_multiply(*a.limbs(), *b.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
//
|
||||
// Special routines for multiplying two integers to obtain a multiprecision result:
|
||||
//
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
signed_double_limb_type a, signed_double_limb_type b)
|
||||
{
|
||||
static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
|
||||
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
bool s = false;
|
||||
double_limb_type w, x, y, z;
|
||||
if(a < 0)
|
||||
{
|
||||
a = -a;
|
||||
s = true;
|
||||
}
|
||||
if(b < 0)
|
||||
{
|
||||
b = -b;
|
||||
s = !s;
|
||||
}
|
||||
w = a & mask;
|
||||
x = a >> limb_bits;
|
||||
y = b & mask;
|
||||
z = b >> limb_bits;
|
||||
|
||||
result.resize(4, 4);
|
||||
limb_type* pr = result.limbs();
|
||||
|
||||
double_limb_type carry = w * y;
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += w * z + x * y;
|
||||
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += x * z;
|
||||
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#else
|
||||
pr[0] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += w * z + x * y;
|
||||
pr[1] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += x * z;
|
||||
pr[2] = static_cast<limb_type>(carry);
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#endif
|
||||
result.sign(s);
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
double_limb_type a, double_limb_type b)
|
||||
{
|
||||
static const signed_double_limb_type mask = ~static_cast<limb_type>(0);
|
||||
static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
|
||||
|
||||
double_limb_type w, x, y, z;
|
||||
w = a & mask;
|
||||
x = a >> limb_bits;
|
||||
y = b & mask;
|
||||
z = b >> limb_bits;
|
||||
|
||||
result.resize(4, 4);
|
||||
limb_type* pr = result.limbs();
|
||||
|
||||
double_limb_type carry = w * y;
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
pr[0] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += w * z;
|
||||
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry = x * y + pr[1];
|
||||
pr[1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
carry >>= limb_bits;
|
||||
carry += pr[2] + x * z;
|
||||
pr[2] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#else
|
||||
pr[0] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += w * z;
|
||||
pr[1] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
pr[2] = static_cast<limb_type>(carry);
|
||||
carry = x * y + pr[1];
|
||||
pr[1] = static_cast<limb_type>(carry);
|
||||
carry >>= limb_bits;
|
||||
carry += pr[2] + x * z;
|
||||
pr[2] = static_cast<limb_type>(carry);
|
||||
pr[3] = static_cast<limb_type>(carry >> limb_bits);
|
||||
#endif
|
||||
result.sign(false);
|
||||
result.normalize();
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1,
|
||||
unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<
|
||||
!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
&& is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
|
||||
>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& a,
|
||||
cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> const& b)
|
||||
{
|
||||
typedef typename boost::multiprecision::detail::canonical<typename cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>::local_limb_type, cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::type canonical_type;
|
||||
eval_multiply(result, static_cast<canonical_type>(*a.limbs()), static_cast<canonical_type>(*b.limbs()));
|
||||
result.sign(a.sign() != b.sign());
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class SI>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<SI>::value && (sizeof(SI) <= sizeof(signed_double_limb_type) / 2)>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
SI a, SI b)
|
||||
{
|
||||
result = static_cast<signed_double_limb_type>(a) * static_cast<signed_double_limb_type>(b);
|
||||
}
|
||||
|
||||
template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class UI>
|
||||
BOOST_MP_FORCEINLINE typename enable_if_c<is_unsigned<UI>::value && (sizeof(UI) <= sizeof(signed_double_limb_type) / 2)>::type
|
||||
eval_multiply(
|
||||
cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
||||
UI a, UI b)
|
||||
{
|
||||
result = static_cast<double_limb_type>(a) * static_cast<double_limb_type>(b);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -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, unsigned 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, unsigned 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, unsigned 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, unsigned 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,261 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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>
|
||||
|
||||
#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
|
||||
BOOST_FORCEINLINE unsigned find_msb(unsigned __int128 mask, mpl::int_<0> const&)
|
||||
{
|
||||
union { unsigned __int128 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(unsigned __int128 mask, mpl::int_<0> const&)
|
||||
{
|
||||
union { unsigned __int128 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
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,884 @@
|
||||
|
||||
// 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<is_integral<U> >::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);
|
||||
|
||||
// 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>
|
||||
inline typename enable_if<is_floating_point<A>, void>::type 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>
|
||||
inline typename enable_if<is_arithmetic<A>, void>::type 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,825 @@
|
||||
|
||||
// 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>());
|
||||
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));
|
||||
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
|
||||
+530
@@ -0,0 +1,530 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
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>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // 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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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 BOOST_MP_MOVE(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,660 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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 bool 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, 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, 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, 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, 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<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_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 bool 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, 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, 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, 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, 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<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_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 bool 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, 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, 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, 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, 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<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_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 bool 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, 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, 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, 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, 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<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_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,20 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
{
|
||||
typedef typename my_allocator::template rebind<value_type>::other type;
|
||||
};
|
||||
} } } } // 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,732 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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> {};
|
||||
template<>
|
||||
struct number_category<float128_type> : public mpl::int_<number_kind_floating_point> {};
|
||||
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // 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,571 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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");
|
||||
}
|
||||
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>
|
||||
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, unsigned 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, unsigned 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, unsigned 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, unsigned 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());
|
||||
}
|
||||
|
||||
} // 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
@@ -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,365 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
{
|
||||
return eval_is_zero(val.data().numerator().backend());
|
||||
}
|
||||
template <class IntBackend>
|
||||
inline int eval_get_sign(const rational_adaptor<IntBackend>& val)
|
||||
{
|
||||
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 T>
|
||||
struct component_type<rational_adaptor<T> >
|
||||
{
|
||||
typedef number<T> 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,779 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
+90
@@ -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
|
||||
|
||||
+28
@@ -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
|
||||
|
||||
+48
@@ -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