/////////////////////////////////////////////////////////////////////////////// // 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_BN_MPFR_HPP #define BOOST_MATH_BN_MPFR_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_MULTIPRECISION_MPFR_DEFAULT_PRECISION #define BOOST_MULTIPRECISION_MPFR_DEFAULT_PRECISION 20 #endif namespace boost { namespace multiprecision { enum mpfr_allocation_type { allocate_stack, allocate_dynamic }; namespace backends { template struct mpfr_float_backend; template <> struct mpfr_float_backend<0, allocate_stack>; } // namespace backends template struct number_category > : public std::integral_constant {}; namespace backends { namespace detail { template struct mpfr_cleanup { // // There are 2 seperate cleanup objects here, one calls // mpfr_free_cache on destruction to perform global cleanup // the other is declared thread_local and calls // mpfr_free_cache2(MPFR_FREE_LOCAL_CACHE) to free thread local data. // struct initializer { initializer() {} ~initializer() { mpfr_free_cache(); } void force_instantiate() const {} }; #if MPFR_VERSION_MAJOR >= 4 struct thread_initializer { thread_initializer() {} ~thread_initializer() { mpfr_free_cache2(MPFR_FREE_LOCAL_CACHE); } void force_instantiate() const {} }; #endif static const initializer init; static void force_instantiate() { #if MPFR_VERSION_MAJOR >= 4 static const BOOST_MP_THREAD_LOCAL thread_initializer thread_init; thread_init.force_instantiate(); #endif init.force_instantiate(); } }; template typename mpfr_cleanup::initializer const mpfr_cleanup::init; inline void mpfr_copy_precision(mpfr_t dest, const mpfr_t src) { mpfr_prec_t p_dest = mpfr_get_prec(dest); mpfr_prec_t p_src = mpfr_get_prec(src); if (p_dest != p_src) mpfr_set_prec(dest, p_src); } inline void mpfr_copy_precision(mpfr_t dest, const mpfr_t src1, const mpfr_t src2) { mpfr_prec_t p_dest = mpfr_get_prec(dest); mpfr_prec_t p_src1 = mpfr_get_prec(src1); mpfr_prec_t p_src2 = mpfr_get_prec(src2); if (p_src2 > p_src1) p_src1 = p_src2; if (p_dest != p_src1) mpfr_set_prec(dest, p_src1); } template struct mpfr_float_imp; template struct mpfr_float_imp { #ifdef BOOST_HAS_LONG_LONG using signed_types = std::tuple ; using unsigned_types = std::tuple; #else using signed_types = std::tuple ; using unsigned_types = std::tuple; #endif using float_types = std::tuple; using exponent_type = long ; mpfr_float_imp() { mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_ui(m_data, 0u, GMP_RNDN); } mpfr_float_imp(unsigned digits2) { mpfr_init2(m_data, digits2); mpfr_set_ui(m_data, 0u, GMP_RNDN); } mpfr_float_imp(const mpfr_float_imp& o) { mpfr_init2(m_data, mpfr_get_prec(o.m_data)); if (o.m_data[0]._mpfr_d) mpfr_set(m_data, o.m_data, GMP_RNDN); } // rvalue copy mpfr_float_imp(mpfr_float_imp&& o) noexcept { m_data[0] = o.m_data[0]; o.m_data[0]._mpfr_d = 0; } mpfr_float_imp& operator=(const mpfr_float_imp& o) { if ((o.m_data[0]._mpfr_d) && (this != &o)) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, mpfr_get_prec(o.m_data)); mpfr_set(m_data, o.m_data, GMP_RNDN); } return *this; } // rvalue assign mpfr_float_imp& operator=(mpfr_float_imp&& o) noexcept { mpfr_swap(m_data, o.m_data); return *this; } #ifdef BOOST_HAS_LONG_LONG #ifdef _MPFR_H_HAVE_INTMAX_T mpfr_float_imp& operator=(boost::ulong_long_type i) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_uj(m_data, i, GMP_RNDN); return *this; } mpfr_float_imp& operator=(boost::long_long_type i) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_sj(m_data, i, GMP_RNDN); return *this; } #else mpfr_float_imp& operator=(boost::ulong_long_type i) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); boost::ulong_long_type mask = ((((1uLL << (std::numeric_limits::digits - 1)) - 1) << 1) | 1uLL); unsigned shift = 0; mpfr_t t; mpfr_init2(t, (std::max)(static_cast(std::numeric_limits::digits), static_cast(mpfr_get_prec(m_data)))); mpfr_set_ui(m_data, 0, GMP_RNDN); while (i) { mpfr_set_ui(t, static_cast(i & mask), GMP_RNDN); if (shift) mpfr_mul_2exp(t, t, shift, GMP_RNDN); mpfr_add(m_data, m_data, t, GMP_RNDN); shift += std::numeric_limits::digits; i >>= std::numeric_limits::digits; } mpfr_clear(t); return *this; } mpfr_float_imp& operator=(boost::long_long_type i) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); bool neg = i < 0; *this = boost::multiprecision::detail::unsigned_abs(i); if (neg) mpfr_neg(m_data, m_data, GMP_RNDN); return *this; } #endif #endif mpfr_float_imp& operator=(unsigned long i) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_ui(m_data, i, GMP_RNDN); return *this; } mpfr_float_imp& operator=(long i) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_si(m_data, i, GMP_RNDN); return *this; } mpfr_float_imp& operator=(double d) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_d(m_data, d, GMP_RNDN); return *this; } mpfr_float_imp& operator=(long double a) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); mpfr_set_ld(m_data, a, GMP_RNDN); return *this; } mpfr_float_imp& operator=(const char* s) { if (m_data[0]._mpfr_d == 0) mpfr_init2(m_data, multiprecision::detail::digits10_2_2(digits10 ? digits10 : (unsigned)get_default_precision())); if (mpfr_set_str(m_data, s, 10, GMP_RNDN) != 0) { BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Unable to parse string \"") + s + std::string("\"as a valid floating point number."))); } return *this; } void swap(mpfr_float_imp& o) noexcept { mpfr_swap(m_data, o.m_data); } std::string str(std::streamsize digits, std::ios_base::fmtflags f) const { BOOST_ASSERT(m_data[0]._mpfr_d); bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific; bool fixed = (f & std::ios_base::fixed) == std::ios_base::fixed; std::streamsize org_digits(digits); if (scientific && digits) ++digits; std::string result; mp_exp_t e; if (mpfr_inf_p(m_data)) { if (mpfr_sgn(m_data) < 0) result = "-inf"; else if (f & std::ios_base::showpos) result = "+inf"; else result = "inf"; return result; } if (mpfr_nan_p(m_data)) { result = "nan"; return result; } if (mpfr_zero_p(m_data)) { e = 0; result = "0"; } else { char* ps = mpfr_get_str(0, &e, 10, static_cast(digits), m_data, GMP_RNDN); --e; // To match with what our formatter expects. if (fixed && e != -1) { // Oops we actually need a different number of digits to what we asked for: mpfr_free_str(ps); digits += e + 1; if (digits == 0) { // We need to get *all* the digits and then possibly round up, // we end up with either "0" or "1" as the result. ps = mpfr_get_str(0, &e, 10, 0, m_data, GMP_RNDN); --e; unsigned offset = *ps == '-' ? 1 : 0; if (ps[offset] > '5') { ++e; ps[offset] = '1'; ps[offset + 1] = 0; } else if (ps[offset] == '5') { unsigned i = offset + 1; bool round_up = false; while (ps[i] != 0) { if (ps[i] != '0') { round_up = true; break; } ++i; } if (round_up) { ++e; ps[offset] = '1'; ps[offset + 1] = 0; } else { ps[offset] = '0'; ps[offset + 1] = 0; } } else { ps[offset] = '0'; ps[offset + 1] = 0; } } else if (digits > 0) { mp_exp_t old_e = e; ps = mpfr_get_str(0, &e, 10, static_cast(digits), m_data, GMP_RNDN); --e; // To match with what our formatter expects. if (old_e > e) { // in some cases, when we ask for more digits of precision, it will // change the number of digits to the left of the decimal, if that // happens, account for it here. // example: cout << fixed << setprecision(3) << mpf_float_50("99.9809") mpfr_free_str(ps); digits -= old_e - e; ps = mpfr_get_str(0, &e, 10, static_cast(digits), m_data, GMP_RNDN); --e; // To match with what our formatter expects. } } else { ps = mpfr_get_str(0, &e, 10, 1, m_data, GMP_RNDN); --e; unsigned offset = *ps == '-' ? 1 : 0; ps[offset] = '0'; ps[offset + 1] = 0; } } result = ps ? ps : "0"; if (ps) mpfr_free_str(ps); } boost::multiprecision::detail::format_float_string(result, e, org_digits, f, 0 != mpfr_zero_p(m_data)); return result; } ~mpfr_float_imp() noexcept { if (m_data[0]._mpfr_d) mpfr_clear(m_data); detail::mpfr_cleanup::force_instantiate(); } void negate() noexcept { BOOST_ASSERT(m_data[0]._mpfr_d); mpfr_neg(m_data, m_data, GMP_RNDN); } template int compare(const mpfr_float_backend& o) const { BOOST_ASSERT(m_data[0]._mpfr_d && o.m_data[0]._mpfr_d); return mpfr_cmp(m_data, o.m_data); } int compare(long i) const { BOOST_ASSERT(m_data[0]._mpfr_d); return mpfr_cmp_si(m_data, i); } int compare(double i) const { BOOST_ASSERT(m_data[0]._mpfr_d); return mpfr_cmp_d(m_data, i); } int compare(long double i) const { BOOST_ASSERT(m_data[0]._mpfr_d); return mpfr_cmp_ld(m_data, i); } int compare(unsigned long i) const { BOOST_ASSERT(m_data[0]._mpfr_d); return mpfr_cmp_ui(m_data, i); } template int compare(V v) const { mpfr_float_backend d(0uL, mpfr_get_prec(m_data)); d = v; return compare(d); } mpfr_t& data() noexcept { BOOST_ASSERT(m_data[0]._mpfr_d); return m_data; } const mpfr_t& data() const noexcept { BOOST_ASSERT(m_data[0]._mpfr_d); return m_data; } protected: mpfr_t m_data; static boost::multiprecision::detail::precision_type& get_default_precision() noexcept { static boost::multiprecision::detail::precision_type val(BOOST_MULTIPRECISION_MPFR_DEFAULT_PRECISION); return val; } }; #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable : 4127) // Conditional expression is constant #endif template struct mpfr_float_imp { #ifdef BOOST_HAS_LONG_LONG using signed_types = std::tuple ; using unsigned_types = std::tuple; #else using signed_types = std::tuple ; using unsigned_types = std::tuple; #endif using float_types = std::tuple; using exponent_type = long ; static constexpr const unsigned digits2 = (digits10 * 1000uL) / 301uL + ((digits10 * 1000uL) % 301 ? 2u : 1u); static constexpr const unsigned limb_count = mpfr_custom_get_size(digits2) / sizeof(mp_limb_t); ~mpfr_float_imp() noexcept { detail::mpfr_cleanup::force_instantiate(); } mpfr_float_imp() { mpfr_custom_init(m_buffer, digits2); mpfr_custom_init_set(m_data, MPFR_NAN_KIND, 0, digits2, m_buffer); mpfr_set_ui(m_data, 0u, GMP_RNDN); } mpfr_float_imp(const mpfr_float_imp& o) { mpfr_custom_init(m_buffer, digits2); mpfr_custom_init_set(m_data, MPFR_NAN_KIND, 0, digits2, m_buffer); mpfr_set(m_data, o.m_data, GMP_RNDN); } mpfr_float_imp& operator=(const mpfr_float_imp& o) { mpfr_set(m_data, o.m_data, GMP_RNDN); return *this; } #ifdef BOOST_HAS_LONG_LONG #ifdef _MPFR_H_HAVE_INTMAX_T mpfr_float_imp& operator=(boost::ulong_long_type i) { mpfr_set_uj(m_data, i, GMP_RNDN); return *this; } mpfr_float_imp& operator=(boost::long_long_type i) { mpfr_set_sj(m_data, i, GMP_RNDN); return *this; } #else mpfr_float_imp& operator=(boost::ulong_long_type i) { boost::ulong_long_type mask = ((((1uLL << (std::numeric_limits::digits - 1)) - 1) << 1) | 1uL); unsigned shift = 0; mpfr_t t; mp_limb_t t_limbs[limb_count]; mpfr_custom_init(t_limbs, digits2); mpfr_custom_init_set(t, MPFR_NAN_KIND, 0, digits2, t_limbs); mpfr_set_ui(m_data, 0, GMP_RNDN); while (i) { mpfr_set_ui(t, static_cast(i & mask), GMP_RNDN); if (shift) mpfr_mul_2exp(t, t, shift, GMP_RNDN); mpfr_add(m_data, m_data, t, GMP_RNDN); shift += std::numeric_limits::digits; i >>= std::numeric_limits::digits; } return *this; } mpfr_float_imp& operator=(boost::long_long_type i) { bool neg = i < 0; *this = boost::multiprecision::detail::unsigned_abs(i); if (neg) mpfr_neg(m_data, m_data, GMP_RNDN); return *this; } #endif #endif mpfr_float_imp& operator=(unsigned long i) { mpfr_set_ui(m_data, i, GMP_RNDN); return *this; } mpfr_float_imp& operator=(long i) { mpfr_set_si(m_data, i, GMP_RNDN); return *this; } mpfr_float_imp& operator=(double d) { mpfr_set_d(m_data, d, GMP_RNDN); return *this; } mpfr_float_imp& operator=(long double a) { mpfr_set_ld(m_data, a, GMP_RNDN); return *this; } mpfr_float_imp& operator=(const char* s) { if (mpfr_set_str(m_data, s, 10, GMP_RNDN) != 0) { BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Unable to parse string \"") + s + std::string("\"as a valid floating point number."))); } return *this; } void swap(mpfr_float_imp& o) noexcept { // We have to swap by copying: mpfr_float_imp t(*this); *this = o; o = t; } std::string str(std::streamsize digits, std::ios_base::fmtflags f) const { BOOST_ASSERT(m_data[0]._mpfr_d); bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific; bool fixed = (f & std::ios_base::fixed) == std::ios_base::fixed; std::streamsize org_digits(digits); if (scientific && digits) ++digits; std::string result; mp_exp_t e; if (mpfr_inf_p(m_data)) { if (mpfr_sgn(m_data) < 0) result = "-inf"; else if (f & std::ios_base::showpos) result = "+inf"; else result = "inf"; return result; } if (mpfr_nan_p(m_data)) { result = "nan"; return result; } if (mpfr_zero_p(m_data)) { e = 0; result = "0"; } else { char* ps = mpfr_get_str(0, &e, 10, static_cast(digits), m_data, GMP_RNDN); --e; // To match with what our formatter expects. if (fixed && e != -1) { // Oops we actually need a different number of digits to what we asked for: mpfr_free_str(ps); digits += e + 1; if (digits == 0) { // We need to get *all* the digits and then possibly round up, // we end up with either "0" or "1" as the result. ps = mpfr_get_str(0, &e, 10, 0, m_data, GMP_RNDN); --e; unsigned offset = *ps == '-' ? 1 : 0; if (ps[offset] > '5') { ++e; ps[offset] = '1'; ps[offset + 1] = 0; } else if (ps[offset] == '5') { unsigned i = offset + 1; bool round_up = false; while (ps[i] != 0) { if (ps[i] != '0') { round_up = true; break; } } if (round_up) { ++e; ps[offset] = '1'; ps[offset + 1] = 0; } else { ps[offset] = '0'; ps[offset + 1] = 0; } } else { ps[offset] = '0'; ps[offset + 1] = 0; } } else if (digits > 0) { ps = mpfr_get_str(0, &e, 10, static_cast(digits), m_data, GMP_RNDN); --e; // To match with what our formatter expects. } else { ps = mpfr_get_str(0, &e, 10, 1, m_data, GMP_RNDN); --e; unsigned offset = *ps == '-' ? 1 : 0; ps[offset] = '0'; ps[offset + 1] = 0; } } result = ps ? ps : "0"; if (ps) mpfr_free_str(ps); } boost::multiprecision::detail::format_float_string(result, e, org_digits, f, 0 != mpfr_zero_p(m_data)); return result; } void negate() noexcept { mpfr_neg(m_data, m_data, GMP_RNDN); } template int compare(const mpfr_float_backend& o) const { return mpfr_cmp(m_data, o.m_data); } int compare(long i) const { return mpfr_cmp_si(m_data, i); } int compare(unsigned long i) const { return mpfr_cmp_ui(m_data, i); } int compare(double i) const { return mpfr_cmp_d(m_data, i); } int compare(long double i) const { return mpfr_cmp_ld(m_data, i); } template int compare(V v) const { mpfr_float_backend d; d = v; return compare(d); } mpfr_t& data() noexcept { return m_data; } const mpfr_t& data() const noexcept { return m_data; } protected: mpfr_t m_data; mp_limb_t m_buffer[limb_count]; }; #ifdef BOOST_MSVC #pragma warning(pop) #endif } // namespace detail template struct mpfr_float_backend : public detail::mpfr_float_imp { mpfr_float_backend() : detail::mpfr_float_imp() {} mpfr_float_backend(const mpfr_float_backend& o) : detail::mpfr_float_imp(o) {} // rvalue copy mpfr_float_backend(mpfr_float_backend&& o) noexcept : detail::mpfr_float_imp(static_cast&&>(o)) {} template mpfr_float_backend(const mpfr_float_backend& val, typename std::enable_if::type* = 0) : detail::mpfr_float_imp() { mpfr_set(this->m_data, val.data(), GMP_RNDN); } template explicit mpfr_float_backend(const mpfr_float_backend& val, typename std::enable_if::type* = 0) : detail::mpfr_float_imp() { mpfr_set(this->m_data, val.data(), GMP_RNDN); } template mpfr_float_backend(const gmp_float& val, typename std::enable_if::type* = 0) : detail::mpfr_float_imp() { mpfr_set_f(this->m_data, val.data(), GMP_RNDN); } template mpfr_float_backend(const gmp_float& val, typename std::enable_if::type* = 0) : detail::mpfr_float_imp() { mpfr_set_f(this->m_data, val.data(), GMP_RNDN); } mpfr_float_backend(const gmp_int& val) : detail::mpfr_float_imp() { mpfr_set_z(this->m_data, val.data(), GMP_RNDN); } mpfr_float_backend(const gmp_rational& val) : detail::mpfr_float_imp() { mpfr_set_q(this->m_data, val.data(), GMP_RNDN); } mpfr_float_backend(const mpfr_t val) : detail::mpfr_float_imp() { mpfr_set(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpf_t val) : detail::mpfr_float_imp() { mpfr_set_f(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpz_t val) : detail::mpfr_float_imp() { mpfr_set_z(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpq_t val) : detail::mpfr_float_imp() { mpfr_set_q(this->m_data, val, GMP_RNDN); } // Construction with precision: we ignore the precision here. template mpfr_float_backend(const V& o, unsigned) { *this = o; } mpfr_float_backend& operator=(const mpfr_float_backend& o) { *static_cast*>(this) = static_cast const&>(o); return *this; } // rvalue assign mpfr_float_backend& operator=(mpfr_float_backend&& o) noexcept { *static_cast*>(this) = static_cast&&>(o); return *this; } template mpfr_float_backend& operator=(const V& v) { *static_cast*>(this) = v; return *this; } mpfr_float_backend& operator=(const mpfr_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpf_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_f(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpz_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_z(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpq_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_q(this->m_data, val, GMP_RNDN); return *this; } // We don't change our precision here, this is a fixed precision type: template mpfr_float_backend& operator=(const mpfr_float_backend& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set(this->m_data, val.data(), GMP_RNDN); return *this; } template mpfr_float_backend& operator=(const gmp_float& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_f(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_int& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_z(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_rational& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_q(this->m_data, val.data(), GMP_RNDN); return *this; } }; template <> struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0, allocate_dynamic> { mpfr_float_backend() : detail::mpfr_float_imp<0, allocate_dynamic>() {} mpfr_float_backend(const mpfr_t val) : detail::mpfr_float_imp<0, allocate_dynamic>((unsigned)mpfr_get_prec(val)) { mpfr_set(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpf_t val) : detail::mpfr_float_imp<0, allocate_dynamic>((unsigned)mpf_get_prec(val)) { mpfr_set_f(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpz_t val) : detail::mpfr_float_imp<0, allocate_dynamic>() { mpfr_set_z(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpq_t val) : detail::mpfr_float_imp<0, allocate_dynamic>() { mpfr_set_q(this->m_data, val, GMP_RNDN); } mpfr_float_backend(const mpfr_float_backend& o) : detail::mpfr_float_imp<0, allocate_dynamic>(o) {} // rvalue copy mpfr_float_backend(mpfr_float_backend&& o) noexcept : detail::mpfr_float_imp<0, allocate_dynamic>(static_cast&&>(o)) {} template mpfr_float_backend(const V& o, unsigned digits10) : detail::mpfr_float_imp<0, allocate_dynamic>(multiprecision::detail::digits10_2_2(digits10)) { *this = o; } #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW mpfr_float_backend(const std::string_view& o, unsigned digits10) : detail::mpfr_float_imp<0, allocate_dynamic>(multiprecision::detail::digits10_2_2(digits10)) { std::string s(o); *this = s.c_str(); } #endif template mpfr_float_backend(const gmp_float& val, unsigned digits10) : detail::mpfr_float_imp<0, allocate_dynamic>(multiprecision::detail::digits10_2_2(digits10)) { mpfr_set_f(this->m_data, val.data(), GMP_RNDN); } template mpfr_float_backend(const mpfr_float_backend& val, unsigned digits10) : detail::mpfr_float_imp<0, allocate_dynamic>(multiprecision::detail::digits10_2_2(digits10)) { mpfr_set(this->m_data, val.data(), GMP_RNDN); } template mpfr_float_backend(const mpfr_float_backend& val) : detail::mpfr_float_imp<0, allocate_dynamic>(mpfr_get_prec(val.data())) { mpfr_set(this->m_data, val.data(), GMP_RNDN); } template mpfr_float_backend(const gmp_float& val) : detail::mpfr_float_imp<0, allocate_dynamic>(mpf_get_prec(val.data())) { mpfr_set_f(this->m_data, val.data(), GMP_RNDN); } mpfr_float_backend(const gmp_int& val) : detail::mpfr_float_imp<0, allocate_dynamic>() { mpfr_set_z(this->m_data, val.data(), GMP_RNDN); } mpfr_float_backend(const gmp_rational& val) : detail::mpfr_float_imp<0, allocate_dynamic>() { mpfr_set_q(this->m_data, val.data(), GMP_RNDN); } mpfr_float_backend& operator=(const mpfr_float_backend& o) { if (this != &o) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, mpfr_get_prec(o.data())); else detail::mpfr_copy_precision(this->m_data, o.data()); mpfr_set(this->m_data, o.data(), GMP_RNDN); } return *this; } // rvalue assign mpfr_float_backend& operator=(mpfr_float_backend&& o) noexcept { *static_cast*>(this) = static_cast&&>(o); return *this; } template mpfr_float_backend& operator=(const V& v) { *static_cast*>(this) = v; return *this; } mpfr_float_backend& operator=(const mpfr_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, mpfr_get_prec(val)); else mpfr_set_prec(this->m_data, mpfr_get_prec(val)); mpfr_set(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpf_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, (mpfr_prec_t)mpf_get_prec(val)); else mpfr_set_prec(this->m_data, (unsigned)mpf_get_prec(val)); mpfr_set_f(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpz_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_z(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpq_t val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_q(this->m_data, val, GMP_RNDN); return *this; } template mpfr_float_backend& operator=(const mpfr_float_backend& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, mpfr_get_prec(val.data())); else mpfr_set_prec(this->m_data, mpfr_get_prec(val.data())); mpfr_set(this->m_data, val.data(), GMP_RNDN); return *this; } template mpfr_float_backend& operator=(const gmp_float& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, mpf_get_prec(val.data())); else mpfr_set_prec(this->m_data, mpf_get_prec(val.data())); mpfr_set_f(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_int& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_z(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_rational& val) { if (this->m_data[0]._mpfr_d == 0) mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_q(this->m_data, val.data(), GMP_RNDN); return *this; } static unsigned default_precision() noexcept { return get_default_precision(); } static void default_precision(unsigned v) noexcept { get_default_precision() = v; } unsigned precision() const noexcept { return multiprecision::detail::digits2_2_10(mpfr_get_prec(this->m_data)); } void precision(unsigned digits10) noexcept { mpfr_prec_round(this->m_data, multiprecision::detail::digits10_2_2((digits10)), GMP_RNDN); } }; template inline typename std::enable_if::value, bool>::type eval_eq(const mpfr_float_backend& a, const T& b) { return a.compare(b) == 0; } template inline typename std::enable_if::value, bool>::type eval_lt(const mpfr_float_backend& a, const T& b) { return a.compare(b) < 0; } template inline typename std::enable_if::value, bool>::type eval_gt(const mpfr_float_backend& a, const T& b) { return a.compare(b) > 0; } template inline bool eval_eq(const mpfr_float_backend& a, const mpfr_float_backend& b)noexcept { return mpfr_equal_p(a.data(), b.data()); } template inline bool eval_lt(const mpfr_float_backend& a, const mpfr_float_backend& b) noexcept { return mpfr_less_p(a.data(), b.data()); } template inline bool eval_gt(const mpfr_float_backend& a, const mpfr_float_backend& b) noexcept { return mpfr_greater_p(a.data(), b.data()); } template inline void eval_add(mpfr_float_backend& result, const mpfr_float_backend& o) { mpfr_add(result.data(), result.data(), o.data(), GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& result, const mpfr_float_backend& o) { mpfr_sub(result.data(), result.data(), o.data(), GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& result, const mpfr_float_backend& o) { if ((void*)&o == (void*)&result) mpfr_sqr(result.data(), o.data(), GMP_RNDN); else mpfr_mul(result.data(), result.data(), o.data(), GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& result, const mpfr_float_backend& o) { mpfr_div(result.data(), result.data(), o.data(), GMP_RNDN); } template inline void eval_add(mpfr_float_backend& result, unsigned long i) { mpfr_add_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& result, unsigned long i) { mpfr_sub_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& result, unsigned long i) { mpfr_mul_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& result, unsigned long i) { mpfr_div_ui(result.data(), result.data(), i, GMP_RNDN); } template inline void eval_add(mpfr_float_backend& result, long i) { if (i > 0) mpfr_add_ui(result.data(), result.data(), i, GMP_RNDN); else mpfr_sub_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& result, long i) { if (i > 0) mpfr_sub_ui(result.data(), result.data(), i, GMP_RNDN); else mpfr_add_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& result, long i) { mpfr_mul_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); if (i < 0) mpfr_neg(result.data(), result.data(), GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& result, long i) { mpfr_div_ui(result.data(), result.data(), boost::multiprecision::detail::unsigned_abs(i), GMP_RNDN); if (i < 0) mpfr_neg(result.data(), result.data(), GMP_RNDN); } // // Specialised 3 arg versions of the basic operators: // template inline void eval_add(mpfr_float_backend& a, const mpfr_float_backend& x, const mpfr_float_backend& y) { mpfr_add(a.data(), x.data(), y.data(), GMP_RNDN); } template inline void eval_add(mpfr_float_backend& a, const mpfr_float_backend& x, unsigned long y) { mpfr_add_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_add(mpfr_float_backend& a, const mpfr_float_backend& x, long y) { if (y < 0) mpfr_sub_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDN); else mpfr_add_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_add(mpfr_float_backend& a, unsigned long x, const mpfr_float_backend& y) { mpfr_add_ui(a.data(), y.data(), x, GMP_RNDN); } template inline void eval_add(mpfr_float_backend& a, long x, const mpfr_float_backend& y) { if (x < 0) { mpfr_ui_sub(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data(), GMP_RNDN); mpfr_neg(a.data(), a.data(), GMP_RNDN); } else mpfr_add_ui(a.data(), y.data(), x, GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& a, const mpfr_float_backend& x, const mpfr_float_backend& y) { mpfr_sub(a.data(), x.data(), y.data(), GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& a, const mpfr_float_backend& x, unsigned long y) { mpfr_sub_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& a, const mpfr_float_backend& x, long y) { if (y < 0) mpfr_add_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDN); else mpfr_sub_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& a, unsigned long x, const mpfr_float_backend& y) { mpfr_ui_sub(a.data(), x, y.data(), GMP_RNDN); } template inline void eval_subtract(mpfr_float_backend& a, long x, const mpfr_float_backend& y) { if (x < 0) { mpfr_add_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x), GMP_RNDN); mpfr_neg(a.data(), a.data(), GMP_RNDN); } else mpfr_ui_sub(a.data(), x, y.data(), GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& a, const mpfr_float_backend& x, const mpfr_float_backend& y) { if ((void*)&x == (void*)&y) mpfr_sqr(a.data(), x.data(), GMP_RNDN); else mpfr_mul(a.data(), x.data(), y.data(), GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& a, const mpfr_float_backend& x, unsigned long y) { mpfr_mul_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& a, const mpfr_float_backend& x, long y) { if (y < 0) { mpfr_mul_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDN); a.negate(); } else mpfr_mul_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& a, unsigned long x, const mpfr_float_backend& y) { mpfr_mul_ui(a.data(), y.data(), x, GMP_RNDN); } template inline void eval_multiply(mpfr_float_backend& a, long x, const mpfr_float_backend& y) { if (x < 0) { mpfr_mul_ui(a.data(), y.data(), boost::multiprecision::detail::unsigned_abs(x), GMP_RNDN); mpfr_neg(a.data(), a.data(), GMP_RNDN); } else mpfr_mul_ui(a.data(), y.data(), x, GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& a, const mpfr_float_backend& x, const mpfr_float_backend& y) { mpfr_div(a.data(), x.data(), y.data(), GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& a, const mpfr_float_backend& x, unsigned long y) { mpfr_div_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& a, const mpfr_float_backend& x, long y) { if (y < 0) { mpfr_div_ui(a.data(), x.data(), boost::multiprecision::detail::unsigned_abs(y), GMP_RNDN); a.negate(); } else mpfr_div_ui(a.data(), x.data(), y, GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& a, unsigned long x, const mpfr_float_backend& y) { mpfr_ui_div(a.data(), x, y.data(), GMP_RNDN); } template inline void eval_divide(mpfr_float_backend& a, long x, const mpfr_float_backend& y) { if (x < 0) { mpfr_ui_div(a.data(), boost::multiprecision::detail::unsigned_abs(x), y.data(), GMP_RNDN); mpfr_neg(a.data(), a.data(), GMP_RNDN); } else mpfr_ui_div(a.data(), x, y.data(), GMP_RNDN); } template inline bool eval_is_zero(const mpfr_float_backend& val) noexcept { return 0 != mpfr_zero_p(val.data()); } template inline int eval_get_sign(const mpfr_float_backend& val) noexcept { return mpfr_sgn(val.data()); } template inline void eval_convert_to(unsigned long* result, const mpfr_float_backend& val) { if (mpfr_nan_p(val.data())) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer.")); } *result = mpfr_get_ui(val.data(), GMP_RNDZ); } template inline void eval_convert_to(long* result, const mpfr_float_backend& val) { if (mpfr_nan_p(val.data())) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer.")); } *result = mpfr_get_si(val.data(), GMP_RNDZ); } #ifdef _MPFR_H_HAVE_INTMAX_T template inline void eval_convert_to(boost::ulong_long_type* result, const mpfr_float_backend& val) { if (mpfr_nan_p(val.data())) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer.")); } *result = mpfr_get_uj(val.data(), GMP_RNDZ); } template inline void eval_convert_to(boost::long_long_type* result, const mpfr_float_backend& val) { if (mpfr_nan_p(val.data())) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer.")); } *result = mpfr_get_sj(val.data(), GMP_RNDZ); } #endif template inline void eval_convert_to(float* result, const mpfr_float_backend& val) noexcept { *result = mpfr_get_flt(val.data(), GMP_RNDN); } template inline void eval_convert_to(double* result, const mpfr_float_backend& val) noexcept { *result = mpfr_get_d(val.data(), GMP_RNDN); } template inline void eval_convert_to(long double* result, const mpfr_float_backend& val) noexcept { *result = mpfr_get_ld(val.data(), GMP_RNDN); } // // Native non-member operations: // template inline void eval_sqrt(mpfr_float_backend& result, const mpfr_float_backend& val) { mpfr_sqrt(result.data(), val.data(), GMP_RNDN); } template inline void eval_abs(mpfr_float_backend& result, const mpfr_float_backend& val) { mpfr_abs(result.data(), val.data(), GMP_RNDN); } template inline void eval_fabs(mpfr_float_backend& result, const mpfr_float_backend& val) { mpfr_abs(result.data(), val.data(), GMP_RNDN); } template inline void eval_ceil(mpfr_float_backend& result, const mpfr_float_backend& val) { mpfr_ceil(result.data(), val.data()); } template inline void eval_floor(mpfr_float_backend& result, const mpfr_float_backend& val) { mpfr_floor(result.data(), val.data()); } template inline void eval_trunc(mpfr_float_backend& result, const mpfr_float_backend& val) { mpfr_trunc(result.data(), val.data()); } template inline void eval_ldexp(mpfr_float_backend& result, const mpfr_float_backend& val, long e) { if (e > 0) mpfr_mul_2exp(result.data(), val.data(), e, GMP_RNDN); else if (e < 0) mpfr_div_2exp(result.data(), val.data(), -e, GMP_RNDN); else result = val; } template inline void eval_frexp(mpfr_float_backend& result, const mpfr_float_backend& val, int* e) { if (mpfr_zero_p(val.data())) { *e = 0; result = val; return; } mp_exp_t v = mpfr_get_exp(val.data()); *e = v; if (v) eval_ldexp(result, val, -v); else result = val; } template inline void eval_frexp(mpfr_float_backend& result, const mpfr_float_backend& val, long* e) { if (mpfr_zero_p(val.data())) { *e = 0; result = val; return; } mp_exp_t v = mpfr_get_exp(val.data()); *e = v; if(v) eval_ldexp(result, val, -v); else result = val; } template inline int eval_fpclassify(const mpfr_float_backend& val) noexcept { return mpfr_inf_p(val.data()) ? FP_INFINITE : mpfr_nan_p(val.data()) ? FP_NAN : mpfr_zero_p(val.data()) ? FP_ZERO : FP_NORMAL; } template inline void eval_pow(mpfr_float_backend& result, const mpfr_float_backend& b, const mpfr_float_backend& e) { if (mpfr_zero_p(b.data()) && mpfr_integer_p(e.data()) && (mpfr_signbit(e.data()) == 0) && mpfr_fits_ulong_p(e.data(), GMP_RNDN) && (mpfr_get_ui(e.data(), GMP_RNDN) & 1)) { mpfr_set(result.data(), b.data(), GMP_RNDN); } else mpfr_pow(result.data(), b.data(), e.data(), GMP_RNDN); } #ifdef BOOST_MSVC // // The enable_if usage below doesn't work with msvc - but only when // certain other enable_if usages are defined first. It's a capricious // and rather annoying compiler bug in other words.... // #define BOOST_MP_ENABLE_IF_WORKAROUND (Digits10 || !Digits10)&& #else #define BOOST_MP_ENABLE_IF_WORKAROUND #endif template inline typename std::enable_if::value && boost::multiprecision::detail::is_integral::value && (BOOST_MP_ENABLE_IF_WORKAROUND(sizeof(Integer) <= sizeof(long)))>::type eval_pow(mpfr_float_backend& result, const mpfr_float_backend& b, const Integer& e) { mpfr_pow_si(result.data(), b.data(), e, GMP_RNDN); } template inline typename std::enable_if::value && (BOOST_MP_ENABLE_IF_WORKAROUND(sizeof(Integer) <= sizeof(long)))>::type eval_pow(mpfr_float_backend& result, const mpfr_float_backend& b, const Integer& e) { mpfr_pow_ui(result.data(), b.data(), e, GMP_RNDN); } #undef BOOST_MP_ENABLE_IF_WORKAROUND template inline void eval_exp(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_exp(result.data(), arg.data(), GMP_RNDN); } template inline void eval_exp2(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_exp2(result.data(), arg.data(), GMP_RNDN); } template inline void eval_log(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_log(result.data(), arg.data(), GMP_RNDN); } template inline void eval_log10(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_log10(result.data(), arg.data(), GMP_RNDN); } template inline void eval_sin(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_sin(result.data(), arg.data(), GMP_RNDN); } template inline void eval_cos(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_cos(result.data(), arg.data(), GMP_RNDN); } template inline void eval_tan(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_tan(result.data(), arg.data(), GMP_RNDN); } template inline void eval_asin(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_asin(result.data(), arg.data(), GMP_RNDN); } template inline void eval_acos(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_acos(result.data(), arg.data(), GMP_RNDN); } template inline void eval_atan(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_atan(result.data(), arg.data(), GMP_RNDN); } template inline void eval_atan2(mpfr_float_backend& result, const mpfr_float_backend& arg1, const mpfr_float_backend& arg2) { mpfr_atan2(result.data(), arg1.data(), arg2.data(), GMP_RNDN); } template inline void eval_sinh(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_sinh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_cosh(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_cosh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_tanh(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_tanh(result.data(), arg.data(), GMP_RNDN); } template inline void eval_log2(mpfr_float_backend& result, const mpfr_float_backend& arg) { mpfr_log2(result.data(), arg.data(), GMP_RNDN); } template inline void eval_modf(mpfr_float_backend& result, const mpfr_float_backend& arg, mpfr_float_backend* pipart) { if (0 == pipart) { mpfr_float_backend ipart; mpfr_modf(ipart.data(), result.data(), arg.data(), GMP_RNDN); } else { mpfr_modf(pipart->data(), result.data(), arg.data(), GMP_RNDN); } } template inline void eval_remainder(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b) { mpfr_remainder(result.data(), a.data(), b.data(), GMP_RNDN); } template inline void eval_remquo(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b, int* pi) { long l; mpfr_remquo(result.data(), &l, a.data(), b.data(), GMP_RNDN); if (pi) *pi = l; } template inline void eval_fmod(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b) { mpfr_fmod(result.data(), a.data(), b.data(), GMP_RNDN); } template inline void eval_multiply_add(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b) { mpfr_fma(result.data(), a.data(), b.data(), result.data(), GMP_RNDN); } template inline void eval_multiply_add(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b, const mpfr_float_backend& c) { mpfr_fma(result.data(), a.data(), b.data(), c.data(), GMP_RNDN); } template inline void eval_multiply_subtract(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b) { mpfr_fms(result.data(), a.data(), b.data(), result.data(), GMP_RNDN); result.negate(); } template inline void eval_multiply_subtract(mpfr_float_backend& result, const mpfr_float_backend& a, const mpfr_float_backend& b, const mpfr_float_backend& c) { mpfr_fms(result.data(), a.data(), b.data(), c.data(), GMP_RNDN); } template inline int eval_signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const mpfr_float_backend& arg) { return (arg.data()[0]._mpfr_sign < 0) ? 1 : 0; } template inline std::size_t hash_value(const mpfr_float_backend& val) { std::size_t result = 0; std::size_t len = val.data()[0]._mpfr_prec / mp_bits_per_limb; if (val.data()[0]._mpfr_prec % mp_bits_per_limb) ++len; for (std::size_t i = 0; i < len; ++i) boost::hash_combine(result, val.data()[0]._mpfr_d[i]); boost::hash_combine(result, val.data()[0]._mpfr_exp); boost::hash_combine(result, val.data()[0]._mpfr_sign); return result; } } // namespace backends namespace detail { template <> struct is_variable_precision > : public std::integral_constant {}; } // namespace detail template <> struct number_category >::type> : public std::integral_constant {}; template struct is_equivalent_number_type, backends::mpfr_float_backend > : public std::integral_constant {}; using boost::multiprecision::backends::mpfr_float_backend; using mpfr_float_50 = number > ; using mpfr_float_100 = number > ; using mpfr_float_500 = number > ; using mpfr_float_1000 = number >; using mpfr_float = number > ; using static_mpfr_float_50 = number > ; using static_mpfr_float_100 = number >; template inline boost::multiprecision::number, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& a, const boost::multiprecision::number, ExpressionTemplates>& b) { return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? boost::multiprecision::number, ExpressionTemplates>(-a) : a; } template inline boost::multiprecision::number >, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number >, ExpressionTemplates>& a, const boost::multiprecision::number >, ExpressionTemplates>& b) { return (boost::multiprecision::signbit)(a) != (boost::multiprecision::signbit)(b) ? boost::multiprecision::number >, ExpressionTemplates>(-a) : a; } } // namespace multiprecision namespace math { using boost::multiprecision::copysign; using boost::multiprecision::signbit; namespace tools { inline void set_output_precision(const boost::multiprecision::mpfr_float& val, std::ostream& os) { os << std::setprecision(val.precision()); } template <> inline int digits() #ifdef BOOST_MATH_NOEXCEPT noexcept #endif { return multiprecision::detail::digits10_2_2(boost::multiprecision::mpfr_float::default_precision()); } template <> inline int digits, boost::multiprecision::et_off> >() #ifdef BOOST_MATH_NOEXCEPT noexcept #endif { return multiprecision::detail::digits10_2_2(boost::multiprecision::mpfr_float::default_precision()); } template <> inline boost::multiprecision::mpfr_float max_value() { boost::multiprecision::mpfr_float result(0.5); mpfr_mul_2exp(result.backend().data(), result.backend().data(), mpfr_get_emax(), GMP_RNDN); BOOST_ASSERT(mpfr_number_p(result.backend().data())); return result; } template <> inline boost::multiprecision::mpfr_float min_value() { boost::multiprecision::mpfr_float result(0.5); mpfr_div_2exp(result.backend().data(), result.backend().data(), -mpfr_get_emin(), GMP_RNDN); BOOST_ASSERT(mpfr_number_p(result.backend().data())); return result; } template <> inline boost::multiprecision::number, boost::multiprecision::et_off> max_value, boost::multiprecision::et_off> >() { boost::multiprecision::number, boost::multiprecision::et_off> result(0.5); mpfr_mul_2exp(result.backend().data(), result.backend().data(), mpfr_get_emax(), GMP_RNDN); BOOST_ASSERT(mpfr_number_p(result.backend().data())); return result; } template <> inline boost::multiprecision::number, boost::multiprecision::et_off> min_value, boost::multiprecision::et_off> >() { boost::multiprecision::number, boost::multiprecision::et_off> result(0.5); mpfr_div_2exp(result.backend().data(), result.backend().data(), -mpfr_get_emin(), GMP_RNDN); BOOST_ASSERT(mpfr_number_p(result.backend().data())); return result; } template <> inline int digits > >() #ifdef BOOST_MATH_NOEXCEPT noexcept #endif { return multiprecision::detail::digits10_2_2(boost::multiprecision::number >::default_precision()); } template <> inline int digits >, boost::multiprecision::et_off> >() #ifdef BOOST_MATH_NOEXCEPT noexcept #endif { return multiprecision::detail::digits10_2_2(boost::multiprecision::number >::default_precision()); } template <> inline boost::multiprecision::number > max_value > >() { return max_value().backend(); } template <> inline boost::multiprecision::number > min_value > >() { return min_value().backend(); } template <> inline boost::multiprecision::number >, boost::multiprecision::et_off> max_value >, boost::multiprecision::et_off> >() { return max_value().backend(); } template <> inline boost::multiprecision::number >, boost::multiprecision::et_off> min_value >, boost::multiprecision::et_off> >() { return min_value().backend(); } } // namespace tools namespace constants { namespace detail { template struct constant_pi; template struct constant_ln_two; template struct constant_euler; template struct constant_catalan; template struct constant_pi, ExpressionTemplates> > { using result_type = boost::multiprecision::number, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool has_init = false; if (!has_init) { mpfr_const_pi(result.backend().data(), GMP_RNDN); has_init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_pi(result.backend().data(), GMP_RNDN); return result; } }; template struct constant_ln_two, ExpressionTemplates> > { using result_type = boost::multiprecision::number, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool init = false; if (!init) { mpfr_const_log2(result.backend().data(), GMP_RNDN); init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_log2(result.backend().data(), GMP_RNDN); return result; } }; template struct constant_euler, ExpressionTemplates> > { using result_type = boost::multiprecision::number, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool init = false; if (!init) { mpfr_const_euler(result.backend().data(), GMP_RNDN); init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_euler(result.backend().data(), GMP_RNDN); return result; } }; template struct constant_catalan, ExpressionTemplates> > { using result_type = boost::multiprecision::number, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool init = false; if (!init) { mpfr_const_catalan(result.backend().data(), GMP_RNDN); init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_catalan(result.backend().data(), GMP_RNDN); return result; } }; template struct constant_pi >, ExpressionTemplates> > { using result_type = boost::multiprecision::number >, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool has_init = false; if (!has_init) { mpfr_const_pi(result.backend().value().data(), GMP_RNDN); has_init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_pi(result.backend().value().data(), GMP_RNDN); return result; } }; template struct constant_ln_two >, ExpressionTemplates> > { using result_type = boost::multiprecision::number >, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool init = false; if (!init) { mpfr_const_log2(result.backend().value().data(), GMP_RNDN); init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_log2(result.backend().value().data(), GMP_RNDN); return result; } }; template struct constant_euler >, ExpressionTemplates> > { using result_type = boost::multiprecision::number >, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool init = false; if (!init) { mpfr_const_euler(result.backend().value().data(), GMP_RNDN); init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_euler(result.backend().value().data(), GMP_RNDN); return result; } }; template struct constant_catalan >, ExpressionTemplates> > { using result_type = boost::multiprecision::number >, ExpressionTemplates>; template static inline const result_type& get(const std::integral_constant&) { static result_type result; static bool init = false; if (!init) { mpfr_const_catalan(result.backend().value().data(), GMP_RNDN); init = true; } return result; } static inline const result_type get(const std::integral_constant&) { result_type result; mpfr_const_catalan(result.backend().value().data(), GMP_RNDN); return result; } }; }} // namespace constants::detail } // namespace math namespace multiprecision { // // Overloaded special functions which call native mpfr routines: // template inline boost::multiprecision::number, ExpressionTemplates> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_asinh(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_acosh(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_atanh(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_cbrt(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_erf(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_erfc(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_expm1(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_lngamma(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_gamma(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } template inline boost::multiprecision::number, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_log1p(result.backend().data(), arg.backend().data(), GMP_RNDN); return result; } } // namespace multiprecision namespace math { // // Overloaded special functions which call native mpfr routines: // template inline boost::multiprecision::number, ExpressionTemplates> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy&) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_asinh(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("asinh<%1%>(%1%)", 0, Policy()); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("asinh<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); return result; } template inline boost::multiprecision::number, ExpressionTemplates> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return asinh(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy&) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_acosh(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("acosh<%1%>(%1%)", 0, Policy()); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("acosh<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); return result; } template inline boost::multiprecision::number, ExpressionTemplates> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return acosh(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& ) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_atanh(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("atanh<%1%>(%1%)", 0, Policy()); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("atanh<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); return result; } template inline boost::multiprecision::number, ExpressionTemplates> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return atanh(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy&) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_cbrt(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("cbrt<%1%>(%1%)", 0, Policy()); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("cbrt<%1%>(%1%)", "Unknown error, result is a NaN", result, Policy()); return result; } template inline boost::multiprecision::number, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return cbrt(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_erf(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("erf<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("erf<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return erf(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_erfc(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("erfc<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("erfc<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return erfc(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_expm1(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("expm1<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("expm1<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> exm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return expm1(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(boost::multiprecision::number, ExpressionTemplates> arg, int* sign, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); (void)precision_guard; // warning suppression boost::multiprecision::number, ExpressionTemplates> result; if (arg > 0) { mpfr_lngamma(result.backend().data(), arg.backend().data(), GMP_RNDN); if (sign) *sign = 1; } else { if (floor(arg) == arg) return policies::raise_pole_error, ExpressionTemplates> >( "lgamma<%1%>", "Evaluation of lgamma at a negative integer %1%.", arg, pol); boost::multiprecision::number, ExpressionTemplates> t = detail::sinpx(arg); arg = -arg; if (t < 0) { t = -t; } result = boost::multiprecision::log(boost::math::constants::pi, ExpressionTemplates> >()) - lgamma(arg, 0, pol) - boost::multiprecision::log(t); if (sign) { boost::multiprecision::number, ExpressionTemplates> phase = 1 - arg; phase = floor(phase) / 2; if (floor(phase) == phase) *sign = -1; else *sign = 1; } } if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("lgamma<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("lgamma<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, int* sign) { return lgamma(arg, sign, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { return lgamma(arg, 0, pol); } template inline boost::multiprecision::number, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return lgamma(arg, 0, policies::policy<>()); } template inline typename std::enable_if::value, boost::multiprecision::number, ExpressionTemplates> >::type tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_gamma(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("tgamma<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("tgamma<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return tgamma(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_log1p(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return (arg == -1 ? -1 : 1) * policies::raise_overflow_error, ExpressionTemplates> >("log1p<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("log1p<%1%>(%1%)", "Unknown error, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return log1p(arg, policies::policy<>()); } template inline boost::multiprecision::number, ExpressionTemplates> rsqrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg, const Policy& pol) { boost::multiprecision::detail::scoped_default_precision, ExpressionTemplates> > precision_guard(arg); boost::multiprecision::number, ExpressionTemplates> result; mpfr_rec_sqrt(result.backend().data(), arg.backend().data(), GMP_RNDN); if (mpfr_inf_p(result.backend().data())) return policies::raise_overflow_error, ExpressionTemplates> >("rsqrt<%1%>(%1%)", 0, pol); if (mpfr_nan_p(result.backend().data())) return policies::raise_evaluation_error("rsqrt<%1%>(%1%)", "Negative argument, result is a NaN", result, pol); return result; } template inline boost::multiprecision::number, ExpressionTemplates> rsqrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number, ExpressionTemplates>& arg) { return rsqrt(arg, policies::policy<>()); } } // namespace math } // namespace boost namespace std { // // numeric_limits [partial] specializations for the types declared in this header: // template class numeric_limits, ExpressionTemplates> > { using number_type = boost::multiprecision::number, ExpressionTemplates>; public: static constexpr bool is_specialized = true; static number_type(min)() { static std::pair value; if (!value.first) { value.first = true; value.second = 0.5; mpfr_div_2exp(value.second.backend().data(), value.second.backend().data(), -mpfr_get_emin(), GMP_RNDN); } return value.second; } static number_type(max)() { static std::pair value; if (!value.first) { value.first = true; value.second = 0.5; mpfr_mul_2exp(value.second.backend().data(), value.second.backend().data(), mpfr_get_emax(), GMP_RNDN); } return value.second; } static constexpr number_type lowest() { return -(max)(); } static constexpr int digits = static_cast((Digits10 * 1000L) / 301L + ((Digits10 * 1000L) % 301 ? 2 : 1)); static constexpr int digits10 = Digits10; // Is this really correct??? static constexpr int max_digits10 = boost::multiprecision::detail::calc_max_digits10::value; static constexpr bool is_signed = true; static constexpr bool is_integer = false; static constexpr bool is_exact = false; static constexpr int radix = 2; static number_type epsilon() { static std::pair value; if (!value.first) { value.first = true; value.second = 1; mpfr_div_2exp(value.second.backend().data(), value.second.backend().data(), std::numeric_limits::digits - 1, GMP_RNDN); } return value.second; } // What value should this be???? static number_type round_error() { // returns epsilon/2 static std::pair value; if (!value.first) { value.first = true; value.second = 1; mpfr_div_2exp(value.second.backend().data(), value.second.backend().data(), 1, GMP_RNDN); } return value.second; } static constexpr long min_exponent = MPFR_EMIN_DEFAULT; static constexpr long min_exponent10 = (MPFR_EMIN_DEFAULT / 1000) * 301L; static constexpr long max_exponent = MPFR_EMAX_DEFAULT; static constexpr long max_exponent10 = (MPFR_EMAX_DEFAULT / 1000) * 301L; static constexpr bool has_infinity = true; static constexpr bool has_quiet_NaN = true; static constexpr bool has_signaling_NaN = false; static constexpr float_denorm_style has_denorm = denorm_absent; static constexpr bool has_denorm_loss = false; static number_type infinity() { // returns epsilon/2 static std::pair value; if (!value.first) { value.first = true; value.second = 1; mpfr_set_inf(value.second.backend().data(), 1); } return value.second; } static number_type quiet_NaN() { // returns epsilon/2 static std::pair value; if (!value.first) { value.first = true; value.second = 1; mpfr_set_nan(value.second.backend().data()); } return value.second; } static constexpr number_type signaling_NaN() { return number_type(0); } static constexpr number_type denorm_min() { return number_type(0); } static constexpr bool is_iec559 = false; static constexpr bool is_bounded = true; static constexpr bool is_modulo = false; static constexpr bool traps = true; static constexpr bool tinyness_before = false; static constexpr float_round_style round_style = round_to_nearest; }; template constexpr int numeric_limits, ExpressionTemplates> >::digits; template constexpr int numeric_limits, ExpressionTemplates> >::digits10; template constexpr int numeric_limits, ExpressionTemplates> >::max_digits10; template constexpr bool numeric_limits, ExpressionTemplates> >::is_signed; template constexpr bool numeric_limits, ExpressionTemplates> >::is_integer; template constexpr bool numeric_limits, ExpressionTemplates> >::is_exact; template constexpr int numeric_limits, ExpressionTemplates> >::radix; template constexpr long numeric_limits, ExpressionTemplates> >::min_exponent; template constexpr long numeric_limits, ExpressionTemplates> >::min_exponent10; template constexpr long numeric_limits, ExpressionTemplates> >::max_exponent; template constexpr long numeric_limits, ExpressionTemplates> >::max_exponent10; template constexpr bool numeric_limits, ExpressionTemplates> >::has_infinity; template constexpr bool numeric_limits, ExpressionTemplates> >::has_quiet_NaN; template constexpr bool numeric_limits, ExpressionTemplates> >::has_signaling_NaN; template constexpr float_denorm_style numeric_limits, ExpressionTemplates> >::has_denorm; template constexpr bool numeric_limits, ExpressionTemplates> >::has_denorm_loss; template constexpr bool numeric_limits, ExpressionTemplates> >::is_iec559; template constexpr bool numeric_limits, ExpressionTemplates> >::is_bounded; template constexpr bool numeric_limits, ExpressionTemplates> >::is_modulo; template constexpr bool numeric_limits, ExpressionTemplates> >::traps; template constexpr bool numeric_limits, ExpressionTemplates> >::tinyness_before; template constexpr float_round_style numeric_limits, ExpressionTemplates> >::round_style; template class numeric_limits, ExpressionTemplates> > { using number_type = boost::multiprecision::number, ExpressionTemplates>; public: static constexpr bool is_specialized = false; static number_type(min)() { number_type value(0.5); mpfr_div_2exp(value.backend().data(), value.backend().data(), -mpfr_get_emin(), GMP_RNDN); return value; } static number_type(max)() { number_type value(0.5); mpfr_mul_2exp(value.backend().data(), value.backend().data(), mpfr_get_emax(), GMP_RNDN); return value; } static number_type lowest() { return -(max)(); } static constexpr int digits = INT_MAX; static constexpr int digits10 = INT_MAX; static constexpr int max_digits10 = INT_MAX; static constexpr bool is_signed = true; static constexpr bool is_integer = false; static constexpr bool is_exact = false; static constexpr int radix = 2; static number_type epsilon() { number_type value(1); mpfr_div_2exp(value.backend().data(), value.backend().data(), boost::multiprecision::detail::digits10_2_2(number_type::default_precision()) - 1, GMP_RNDN); return value; } static number_type round_error() { return epsilon() / 2; } static constexpr long min_exponent = MPFR_EMIN_DEFAULT; static constexpr long min_exponent10 = (MPFR_EMIN_DEFAULT / 1000) * 301L; static constexpr long max_exponent = MPFR_EMAX_DEFAULT; static constexpr long max_exponent10 = (MPFR_EMAX_DEFAULT / 1000) * 301L; static constexpr bool has_infinity = true; static constexpr bool has_quiet_NaN = true; static constexpr bool has_signaling_NaN = false; static constexpr float_denorm_style has_denorm = denorm_absent; static constexpr bool has_denorm_loss = false; static number_type infinity() { number_type value; mpfr_set_inf(value.backend().data(), 1); return value; } static number_type quiet_NaN() { number_type value; mpfr_set_nan(value.backend().data()); return value; } static number_type signaling_NaN() { return number_type(0); } static number_type denorm_min() { return number_type(0); } static constexpr bool is_iec559 = false; static constexpr bool is_bounded = true; static constexpr bool is_modulo = false; static constexpr bool traps = false; static constexpr bool tinyness_before = false; static constexpr float_round_style round_style = round_toward_zero; }; template constexpr int numeric_limits, ExpressionTemplates> >::digits; template constexpr int numeric_limits, ExpressionTemplates> >::digits10; template constexpr int numeric_limits, ExpressionTemplates> >::max_digits10; template constexpr bool numeric_limits, ExpressionTemplates> >::is_signed; template constexpr bool numeric_limits, ExpressionTemplates> >::is_integer; template constexpr bool numeric_limits, ExpressionTemplates> >::is_exact; template constexpr int numeric_limits, ExpressionTemplates> >::radix; template constexpr long numeric_limits, ExpressionTemplates> >::min_exponent; template constexpr long numeric_limits, ExpressionTemplates> >::min_exponent10; template constexpr long numeric_limits, ExpressionTemplates> >::max_exponent; template constexpr long numeric_limits, ExpressionTemplates> >::max_exponent10; template constexpr bool numeric_limits, ExpressionTemplates> >::has_infinity; template constexpr bool numeric_limits, ExpressionTemplates> >::has_quiet_NaN; template constexpr bool numeric_limits, ExpressionTemplates> >::has_signaling_NaN; template constexpr float_denorm_style numeric_limits, ExpressionTemplates> >::has_denorm; template constexpr bool numeric_limits, ExpressionTemplates> >::has_denorm_loss; template constexpr bool numeric_limits, ExpressionTemplates> >::is_iec559; template constexpr bool numeric_limits, ExpressionTemplates> >::is_bounded; template constexpr bool numeric_limits, ExpressionTemplates> >::is_modulo; template constexpr bool numeric_limits, ExpressionTemplates> >::traps; template constexpr bool numeric_limits, ExpressionTemplates> >::tinyness_before; template constexpr float_round_style numeric_limits, ExpressionTemplates> >::round_style; } // namespace std #endif