/////////////////////////////////////////////////////////////// // Copyright 2012 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_MATH_FLOAT_BACKEND_HPP #define BOOST_MATH_FLOAT_BACKEND_HPP #include #include #include #include #include #include #include #include #include #include namespace boost { namespace multiprecision { namespace backends { #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable : 4389 4244 4018 4244 4127) #endif template struct arithmetic_backend { typedef mpl::list signed_types; typedef mpl::list unsigned_types; typedef mpl::list float_types; typedef int exponent_type; BOOST_MP_CXX14_CONSTEXPR arithmetic_backend() : m_value(0) {} BOOST_MP_CXX14_CONSTEXPR arithmetic_backend(const arithmetic_backend& o) : m_value(o.m_value) {} template BOOST_MP_CXX14_CONSTEXPR arithmetic_backend(const A& o, const typename enable_if >::type* = 0) : m_value(o) {} template BOOST_MP_CXX14_CONSTEXPR arithmetic_backend(const arithmetic_backend& o) : m_value(o.data()) {} BOOST_MP_CXX14_CONSTEXPR arithmetic_backend& operator=(const arithmetic_backend& o) { m_value = o.m_value; return *this; } template BOOST_MP_CXX14_CONSTEXPR typename enable_if, arithmetic_backend&>::type operator=(A i) { m_value = i; return *this; } template BOOST_MP_CXX14_CONSTEXPR arithmetic_backend& operator=(const arithmetic_backend& i) { m_value = i.data(); return *this; } arithmetic_backend& operator=(const char* s) { #ifndef BOOST_NO_EXCEPTIONS try { #endif m_value = boost::lexical_cast(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; } BOOST_MP_CXX14_CONSTEXPR 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::digits10 + 4) << m_value; return ss.str(); } BOOST_MP_CXX14_CONSTEXPR void do_negate(const mpl::true_&) { m_value = 1 + ~m_value; } BOOST_MP_CXX14_CONSTEXPR void do_negate(const mpl::false_&) { m_value = -m_value; } BOOST_MP_CXX14_CONSTEXPR void negate() { do_negate(mpl::bool_::value>()); } BOOST_MP_CXX14_CONSTEXPR int compare(const arithmetic_backend& o) const { return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0); } template BOOST_MP_CXX14_CONSTEXPR typename enable_if, int>::type compare(A i) const { return m_value > static_cast(i) ? 1 : (m_value < static_cast(i) ? -1 : 0); } BOOST_MP_CXX14_CONSTEXPR Arithmetic& data() { return m_value; } BOOST_MP_CXX14_CONSTEXPR const Arithmetic& data() const { return m_value; } private: Arithmetic m_value; }; template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c::value>::type eval_convert_to(R* result, const arithmetic_backend& backend) { typedef typename boost::common_type::type c_type; BOOST_CONSTEXPR const c_type max = static_cast((std::numeric_limits::max)()); BOOST_CONSTEXPR const c_type min = static_cast((std::numeric_limits::min)()); c_type ct = static_cast(backend.data()); if ((backend.data() < 0) && !std::numeric_limits::is_signed) BOOST_THROW_EXCEPTION(std::range_error("Attempt to convert negative number to unsigned type.")); if (ct > max) *result = boost::is_signed::value ? (std::numeric_limits::max)() : backend.data(); else if (std::numeric_limits::is_signed && (ct < min)) *result = (std::numeric_limits::min)(); else *result = backend.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename disable_if_c::value>::type eval_convert_to(R* result, const arithmetic_backend& backend) { *result = backend.data(); } template inline BOOST_MP_CXX14_CONSTEXPR bool eval_eq(const arithmetic_backend& a, const arithmetic_backend& b) { return a.data() == b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if, bool>::type eval_eq(const arithmetic_backend& a, const A2& b) { return a.data() == static_cast(b); } template inline BOOST_MP_CXX14_CONSTEXPR bool eval_lt(const arithmetic_backend& a, const arithmetic_backend& b) { return a.data() < b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if, bool>::type eval_lt(const arithmetic_backend& a, const A2& b) { return a.data() < static_cast(b); } template inline BOOST_MP_CXX14_CONSTEXPR bool eval_gt(const arithmetic_backend& a, const arithmetic_backend& b) { return a.data() > b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if, bool>::type eval_gt(const arithmetic_backend& a, const A2& b) { return a.data() > static_cast(b); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_add(arithmetic_backend& result, const arithmetic_backend& o) { result.data() += o.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(arithmetic_backend& result, const arithmetic_backend& o) { result.data() -= o.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(arithmetic_backend& result, const arithmetic_backend& o) { result.data() *= o.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c::has_infinity>::type eval_divide(arithmetic_backend& result, const arithmetic_backend& o) { result.data() /= o.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename disable_if_c::has_infinity>::type eval_divide(arithmetic_backend& result, const arithmetic_backend& o) { if (!o.data()) BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero")); result.data() /= o.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if >::type eval_add(arithmetic_backend& result, const A2& o) { result.data() += o; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if >::type eval_subtract(arithmetic_backend& result, const A2& o) { result.data() -= o; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if >::type eval_multiply(arithmetic_backend& result, const A2& o) { result.data() *= o; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<(is_arithmetic::value && !std::numeric_limits::has_infinity)>::type eval_divide(arithmetic_backend& result, const A2& o) { if (!o) BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero")); result.data() /= o; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<(is_arithmetic::value && std::numeric_limits::has_infinity)>::type eval_divide(arithmetic_backend& result, const A2& o) { result.data() /= o; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_add(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { result.data() = a.data() + b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { result.data() = a.data() - b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { result.data() = a.data() * b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c::has_infinity>::type eval_divide(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { result.data() = a.data() / b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename disable_if_c::has_infinity>::type eval_divide(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { if (!b.data()) BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero")); result.data() = a.data() / b.data(); } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if >::type eval_add(arithmetic_backend& result, const arithmetic_backend& a, const A2& b) { result.data() = a.data() + b; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if >::type eval_subtract(arithmetic_backend& result, const arithmetic_backend& a, const A2& b) { result.data() = a.data() - b; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if >::type eval_multiply(arithmetic_backend& result, const arithmetic_backend& a, const A2& b) { result.data() = a.data() * b; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<(is_arithmetic::value && !std::numeric_limits::has_infinity)>::type eval_divide(arithmetic_backend& result, const arithmetic_backend& a, const A2& b) { if (!b) BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero")); result.data() = a.data() / b; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<(is_arithmetic::value && std::numeric_limits::has_infinity)>::type eval_divide(arithmetic_backend& result, const arithmetic_backend& a, const A2& b) { result.data() = a.data() / b; } template inline BOOST_MP_CXX14_CONSTEXPR bool eval_is_zero(const arithmetic_backend& val) { return val.data() == 0; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c< (!std::numeric_limits::is_specialized || std::numeric_limits::is_signed), int>::type eval_get_sign(const arithmetic_backend& val) { return val.data() == 0 ? 0 : val.data() < 0 ? -1 : 1; } template inline BOOST_MP_CXX14_CONSTEXPR typename disable_if_c< (std::numeric_limits::is_specialized || std::numeric_limits::is_signed), int>::type eval_get_sign(const arithmetic_backend& val) { return val.data() == 0 ? 0 : 1; } template inline BOOST_MP_CXX14_CONSTEXPR typename enable_if, T>::type abs(T v) { return v; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_abs(arithmetic_backend& result, const arithmetic_backend& o) { using boost::multiprecision::backends::abs; using std::abs; result.data() = abs(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_fabs(arithmetic_backend& result, const arithmetic_backend& o) { result.data() = std::abs(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_floor(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = floor(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_ceil(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = ceil(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_sqrt(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = sqrt(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR int eval_fpclassify(const arithmetic_backend& o) { return (boost::math::fpclassify)(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_trunc(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = trunc(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_round(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = round(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_frexp(arithmetic_backend& result, const arithmetic_backend& a, int* v) { BOOST_MATH_STD_USING result.data() = frexp(a.data(), v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_ldexp(arithmetic_backend& result, const arithmetic_backend& a, int v) { BOOST_MATH_STD_USING result.data() = ldexp(a.data(), v); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_exp(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = exp(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_log(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = log(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_log10(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = log10(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_sin(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = sin(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_cos(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = cos(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_tan(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = tan(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_acos(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = acos(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_asin(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = asin(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_atan(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = atan(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_sinh(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = sinh(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_cosh(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = cosh(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_tanh(arithmetic_backend& result, const arithmetic_backend& o) { BOOST_MATH_STD_USING result.data() = tanh(o.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_fmod(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { BOOST_MATH_STD_USING result.data() = fmod(a.data(), b.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_pow(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { BOOST_MATH_STD_USING result.data() = pow(a.data(), b.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_atan2(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { BOOST_MATH_STD_USING result.data() = atan2(a.data(), b.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_left_shift(arithmetic_backend& result, I val) { result.data() <<= val; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_right_shift(arithmetic_backend& result, I val) { result.data() >>= val; } template inline BOOST_MP_CXX14_CONSTEXPR void eval_modulus(arithmetic_backend& result, const arithmetic_backend& a) { result.data() %= a.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_and(arithmetic_backend& result, const arithmetic_backend& a) { result.data() &= a.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_or(arithmetic_backend& result, const arithmetic_backend& a) { result.data() |= a.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_bitwise_xor(arithmetic_backend& result, const arithmetic_backend& a) { result.data() ^= a.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_complement(arithmetic_backend& result, const arithmetic_backend& a) { result.data() = ~a.data(); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_gcd(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { result.data() = boost::integer::gcd(a.data(), b.data()); } template inline BOOST_MP_CXX14_CONSTEXPR void eval_lcm(arithmetic_backend& result, const arithmetic_backend& a, const arithmetic_backend& b) { result.data() = boost::integer::lcm(a.data(), b.data()); } template inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const arithmetic_backend& a) { boost::hash hasher; return hasher(a.data()); } #ifdef BOOST_MSVC #pragma warning(pop) #endif } // namespace backends using boost::multiprecision::backends::arithmetic_backend; template struct number_category > : public mpl::int_::value ? number_kind_integer : number_kind_floating_point> {}; namespace detail { template struct double_precision_type; template struct double_precision_type, ET> > { typedef number::type>, ET> type; }; template <> struct double_precision_type > { typedef arithmetic_backend type; }; } // namespace detail }} // namespace boost::multiprecision #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(concepts::real_concept r) { return static_cast(r.value()); } template <> inline int real_cast(concepts::real_concept r) { return static_cast(r.value()); } template <> inline long real_cast(concepts::real_concept r) { return static_cast(r.value()); } // Converts from T to narrower floating-point types, float, double & long double. template <> inline float real_cast(concepts::real_concept r) { return static_cast(r.value()); } template <> inline double real_cast(concepts::real_concept r) { return static_cast(r.value()); } template <> inline long double real_cast(concepts::real_concept r) { return r.value(); } }}} // namespace boost::math::tools #endif namespace std { template class numeric_limits, ExpressionTemplates> > : public std::numeric_limits { typedef std::numeric_limits base_type; typedef boost::multiprecision::number, 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 : public std::numeric_limits { typedef std::numeric_limits 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(); } }; } // namespace std #include #endif