Files
multiprecision/performance/arithmetic_backend.hpp
jzmaddock 75dc2ebb33 Switch floating point types to be zero initialized when default constructed.
This is now consistent between types, and matches what explicitly initialized built in types do.
See https://svn.boost.org/trac/boost/ticket/12500.
2016-10-23 19:12:56 +01:00

645 lines
21 KiB
C++

///////////////////////////////////////////////////////////////
// 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_FLOAT_BACKEND_HPP
#define BOOST_MATH_FLOAT_BACKEND_HPP
#include <iostream>
#include <iomanip>
#include <sstream>
#include <boost/cstdint.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/math/concepts/real_concept.hpp>
#include <boost/multiprecision/number.hpp>
#include <boost/math/common_factor_rt.hpp>
namespace boost{
namespace multiprecision{
namespace backends{
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable:4389 4244 4018 4244 4127)
#endif
template <class Arithmetic>
struct arithmetic_backend
{
typedef mpl::list<short, int, long, long long> signed_types;
typedef mpl::list<unsigned short, unsigned, unsigned long, unsigned long long> unsigned_types;
typedef mpl::list<float, double, long double> float_types;
typedef int exponent_type;
arithmetic_backend()
{
m_value = 0;
}
arithmetic_backend(const arithmetic_backend& o)
{
m_value = o.m_value;
}
template <class A>
arithmetic_backend(const A& o, const typename enable_if<is_arithmetic<A> >::type* = 0) : m_value(o) {}
template <class A>
arithmetic_backend(const arithmetic_backend<A>& o) : m_value(o.data()) {}
arithmetic_backend& operator = (const arithmetic_backend& o)
{
m_value = o.m_value;
return *this;
}
template <class A>
typename enable_if<is_arithmetic<A>, arithmetic_backend&>::type operator = (A i)
{
m_value = i;
return *this;
}
template <class A>
arithmetic_backend& operator = (const arithmetic_backend<A>& i)
{
m_value = i.data();
return *this;
}
arithmetic_backend& operator = (const char* s)
{
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
m_value = boost::lexical_cast<Arithmetic>(s);
#ifndef BOOST_NO_EXCEPTIONS
}
catch(const bad_lexical_cast&)
{
throw std::runtime_error(std::string("Unable to interpret the string provided: \"") + s + std::string("\" as a compatible number type."));
}
#endif
return *this;
}
void swap(arithmetic_backend& o)
{
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);
ss << std::setprecision(digits ? digits : std::numeric_limits<Arithmetic>::digits10 + 4) << m_value;
return ss.str();
}
void do_negate(const mpl::true_&)
{
m_value = 1 + ~m_value;
}
void do_negate(const mpl::false_&)
{
m_value = -m_value;
}
void negate()
{
do_negate(is_unsigned<Arithmetic>());
}
int compare(const arithmetic_backend& o)const
{
return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
}
template <class A>
typename enable_if<is_arithmetic<A>, int>::type compare(A i)const
{
return m_value > static_cast<Arithmetic>(i) ? 1 : (m_value < static_cast<Arithmetic>(i) ? -1 : 0);
}
Arithmetic& data() { return m_value; }
const Arithmetic& data()const { return m_value; }
private:
Arithmetic m_value;
};
template <class R, class Arithmetic>
inline void eval_convert_to(R* result, const arithmetic_backend<Arithmetic>& backend)
{
*result = backend.data();
}
template <class Arithmetic>
inline bool eval_eq(const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
return a.data() == b.data();
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2>, bool>::type eval_eq(const arithmetic_backend<Arithmetic>& a, const A2& b)
{
return a.data() == static_cast<Arithmetic>(b);
}
template <class Arithmetic>
inline bool eval_lt(const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
return a.data() < b.data();
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2>, bool>::type eval_lt(const arithmetic_backend<Arithmetic>& a, const A2& b)
{
return a.data() < static_cast<Arithmetic>(b);
}
template <class Arithmetic>
inline bool eval_gt(const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
return a.data() > b.data();
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2>, bool>::type eval_gt(const arithmetic_backend<Arithmetic>& a, const A2& b)
{
return a.data() > static_cast<Arithmetic>(b);
}
template <class Arithmetic>
inline void eval_add(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
result.data() += o.data();
}
template <class Arithmetic>
inline void eval_subtract(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
result.data() -= o.data();
}
template <class Arithmetic>
inline void eval_multiply(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
result.data() *= o.data();
}
template <class Arithmetic>
inline typename enable_if_c<std::numeric_limits<Arithmetic>::has_infinity>::type eval_divide(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
result.data() /= o.data();
}
template <class Arithmetic>
inline typename disable_if_c<std::numeric_limits<Arithmetic>::has_infinity>::type eval_divide(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
if(!o.data())
BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero"));
result.data() /= o.data();
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2> >::type eval_add(arithmetic_backend<Arithmetic>& result, const A2& o)
{
result.data() += o;
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2> >::type eval_subtract(arithmetic_backend<Arithmetic>& result, const A2& o)
{
result.data() -= o;
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2> >::type eval_multiply(arithmetic_backend<Arithmetic>& result, const A2& o)
{
result.data() *= o;
}
template <class Arithmetic, class A2>
inline typename enable_if_c<(is_arithmetic<A2>::value && !std::numeric_limits<Arithmetic>::has_infinity)>::type
eval_divide(arithmetic_backend<Arithmetic>& result, const A2& o)
{
if(!o)
BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero"));
result.data() /= o;
}
template <class Arithmetic, class A2>
inline typename enable_if_c<(is_arithmetic<A2>::value && std::numeric_limits<Arithmetic>::has_infinity)>::type
eval_divide(arithmetic_backend<Arithmetic>& result, const A2& o)
{
result.data() /= o;
}
template <class Arithmetic>
inline void eval_add(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
result.data() = a.data() + b.data();
}
template <class Arithmetic>
inline void eval_subtract(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
result.data() = a.data() - b.data();
}
template <class Arithmetic>
inline void eval_multiply(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
result.data() = a.data() * b.data();
}
template <class Arithmetic>
inline typename enable_if_c<std::numeric_limits<Arithmetic>::has_infinity>::type eval_divide(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
result.data() = a.data() / b.data();
}
template <class Arithmetic>
inline typename disable_if_c<std::numeric_limits<Arithmetic>::has_infinity>::type eval_divide(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
if(!b.data())
BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero"));
result.data() = a.data() / b.data();
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2> >::type eval_add(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const A2& b)
{
result.data() = a.data() + b;
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2> >::type eval_subtract(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const A2& b)
{
result.data() = a.data() - b;
}
template <class Arithmetic, class A2>
inline typename enable_if<is_arithmetic<A2> >::type eval_multiply(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const A2& b)
{
result.data() = a.data() * b;
}
template <class Arithmetic, class A2>
inline typename enable_if_c<(is_arithmetic<A2>::value && !std::numeric_limits<Arithmetic>::has_infinity)>::type
eval_divide(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const A2& b)
{
if(!b)
BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero"));
result.data() = a.data() / b;
}
template <class Arithmetic, class A2>
inline typename enable_if_c<(is_arithmetic<A2>::value && std::numeric_limits<Arithmetic>::has_infinity)>::type
eval_divide(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const A2& b)
{
result.data() = a.data() / b;
}
template <class Arithmetic>
inline bool eval_is_zero(const arithmetic_backend<Arithmetic>& val)
{
return val.data() == 0;
}
template <class Arithmetic>
inline typename enable_if_c<
(!std::numeric_limits<Arithmetic>::is_specialized
|| std::numeric_limits<Arithmetic>::is_signed), int>::type
eval_get_sign(const arithmetic_backend<Arithmetic>& val)
{
return val.data() == 0 ? 0 : val.data() < 0 ? -1 : 1;
}
template <class Arithmetic>
inline typename disable_if_c<
(std::numeric_limits<Arithmetic>::is_specialized
|| std::numeric_limits<Arithmetic>::is_signed), int>::type
eval_get_sign(const arithmetic_backend<Arithmetic>& val)
{
return val.data() == 0 ? 0 : 1;
}
template <class T>
inline typename enable_if<is_unsigned<T>, T>::type abs(T v) { return v; }
template <class Arithmetic>
inline void eval_abs(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
using std::abs;
using boost::multiprecision::backends::abs;
result.data() = abs(o.data());
}
template <class Arithmetic>
inline void eval_fabs(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
result.data() = std::abs(o.data());
}
template <class Arithmetic>
inline void eval_floor(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = floor(o.data());
}
template <class Arithmetic>
inline void eval_ceil(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = ceil(o.data());
}
template <class Arithmetic>
inline void eval_sqrt(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = sqrt(o.data());
}
template <class Arithmetic>
inline int eval_fpclassify(const arithmetic_backend<Arithmetic>& o)
{
return (boost::math::fpclassify)(o.data());
}
template <class Arithmetic>
inline void eval_trunc(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = trunc(o.data());
}
template <class Arithmetic>
inline void eval_round(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = round(o.data());
}
template <class Arithmetic>
inline void eval_frexp(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, int* v)
{
BOOST_MATH_STD_USING
result.data() = frexp(a.data(), v);
}
template <class Arithmetic>
inline void eval_ldexp(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, int v)
{
BOOST_MATH_STD_USING
result.data() = ldexp(a.data(), v);
}
template <class Arithmetic>
inline void eval_exp(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = exp(o.data());
}
template <class Arithmetic>
inline void eval_log(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = log(o.data());
}
template <class Arithmetic>
inline void eval_log10(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = log10(o.data());
}
template <class Arithmetic>
inline void eval_sin(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = sin(o.data());
}
template <class Arithmetic>
inline void eval_cos(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = cos(o.data());
}
template <class Arithmetic>
inline void eval_tan(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = tan(o.data());
}
template <class Arithmetic>
inline void eval_acos(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = acos(o.data());
}
template <class Arithmetic>
inline void eval_asin(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = asin(o.data());
}
template <class Arithmetic>
inline void eval_atan(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = atan(o.data());
}
template <class Arithmetic>
inline void eval_sinh(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = sinh(o.data());
}
template <class Arithmetic>
inline void eval_cosh(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = cosh(o.data());
}
template <class Arithmetic>
inline void eval_tanh(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& o)
{
BOOST_MATH_STD_USING
result.data() = tanh(o.data());
}
template <class Arithmetic>
inline void eval_fmod(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
BOOST_MATH_STD_USING
result.data() = fmod(a.data(), b.data());
}
template <class Arithmetic>
inline void eval_pow(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
BOOST_MATH_STD_USING
result.data() = pow(a.data(), b.data());
}
template <class Arithmetic>
inline void eval_atan2(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
BOOST_MATH_STD_USING
result.data() = atan2(a.data(), b.data());
}
template <class Arithmetic, class I>
inline void eval_left_shift(arithmetic_backend<Arithmetic>& result, I val)
{
result.data() <<= val;
}
template <class Arithmetic, class I>
inline void eval_right_shift(arithmetic_backend<Arithmetic>& result, I val)
{
result.data() >>= val;
}
template <class Arithmetic>
inline void eval_modulus(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a)
{
result.data() %= a.data();
}
template <class Arithmetic>
inline void eval_bitwise_and(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a)
{
result.data() &= a.data();
}
template <class Arithmetic>
inline void eval_bitwise_or(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a)
{
result.data() |= a.data();
}
template <class Arithmetic>
inline void eval_bitwise_xor(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a)
{
result.data() ^= a.data();
}
template <class Arithmetic>
inline void eval_complement(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a)
{
result.data() = ~a.data();
}
template <class Arithmetic>
inline void eval_gcd(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
result.data() = boost::math::gcd(a.data(), b.data());
}
template <class Arithmetic>
inline void eval_lcm(arithmetic_backend<Arithmetic>& result, const arithmetic_backend<Arithmetic>& a, const arithmetic_backend<Arithmetic>& b)
{
result.data() = boost::math::lcm(a.data(), b.data());
}
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace backends
using boost::multiprecision::backends::arithmetic_backend;
template <class Arithmetic>
struct number_category<arithmetic_backend<Arithmetic> > : public mpl::int_<is_integral<Arithmetic>::value ? number_kind_integer : number_kind_floating_point>{};
namespace detail{
template <class Backend>
struct double_precision_type;
template<class Arithmetic, boost::multiprecision::expression_template_option ET>
struct double_precision_type<number<arithmetic_backend<Arithmetic>, ET> >
{
typedef number<arithmetic_backend<typename double_precision_type<Arithmetic>::type>, ET> type;
};
template<>
struct double_precision_type<arithmetic_backend<boost::int32_t> >
{
typedef arithmetic_backend<boost::int64_t> type;
};
}
}} // namespaces
#if !(defined(__SGI_STL_PORT) || defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS))
//
// We shouldn't need these to get code to compile, however for the sake of
// "level playing field" performance comparisons they avoid the very slow
// lexical_cast's that would otherwise take place. Definition has to be guarded
// by the inverse of pp-logic in real_concept.hpp which defines these as a workaround
// for STLPort plus some other old/broken standartd libraries.
//
namespace boost{ namespace math{ namespace tools{
template <>
inline unsigned int real_cast<unsigned int, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<unsigned int>(r.value());
}
template <>
inline int real_cast<int, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<int>(r.value());
}
template <>
inline long real_cast<long, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<long>(r.value());
}
// Converts from T to narrower floating-point types, float, double & long double.
template <>
inline float real_cast<float, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<float>(r.value());
}
template <>
inline double real_cast<double, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<double>(r.value());
}
template <>
inline long double real_cast<long double, concepts::real_concept>(concepts::real_concept r)
{
return r.value();
}
}}}
#endif
namespace std{
template <class Arithmetic, boost::multiprecision::expression_template_option ExpressionTemplates>
class numeric_limits<boost::multiprecision::number<boost::multiprecision::arithmetic_backend<Arithmetic>, ExpressionTemplates > > : public std::numeric_limits<Arithmetic>
{
typedef std::numeric_limits<Arithmetic> base_type;
typedef boost::multiprecision::number<boost::multiprecision::arithmetic_backend<Arithmetic>, ExpressionTemplates> number_type;
public:
BOOST_STATIC_CONSTEXPR number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
BOOST_STATIC_CONSTEXPR number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
BOOST_STATIC_CONSTEXPR number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
BOOST_STATIC_CONSTEXPR number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
BOOST_STATIC_CONSTEXPR number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
BOOST_STATIC_CONSTEXPR number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
BOOST_STATIC_CONSTEXPR number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
BOOST_STATIC_CONSTEXPR number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
BOOST_STATIC_CONSTEXPR number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
};
template<>
class numeric_limits<boost::math::concepts::real_concept> : public std::numeric_limits<long double>
{
typedef std::numeric_limits<long double> base_type;
typedef boost::math::concepts::real_concept number_type;
public:
static const number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
static const number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
static const number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
static const number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
static const number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
static const number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
static const number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
static const number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
static const number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
};
}
#include <boost/multiprecision/detail/integer_ops.hpp>
#endif