From 1891aaf46836999d0bd154554d9eb201fae925df Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Tue, 31 Dec 2024 04:26:14 +0100 Subject: [PATCH 1/4] Clarify use of boost::float128_type --- .../multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp | 11 +++++++++++ .../cpp_df_qf/cpp_df_qf_detail_ccmath.hpp | 4 ---- .../cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp | 10 +--------- .../cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp | 9 +++++---- .../cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp | 2 +- .../cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp | 10 +--------- .../cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp | 10 +--------- .../cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp | 10 +--------- .../cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp | 10 +--------- 9 files changed, 22 insertions(+), 54 deletions(-) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp index 919d78d2c..9530d4db9 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp @@ -11,7 +11,18 @@ #define BOOST_MP_CPP_DF_QF_DETAIL_2023_01_02_HPP #include + +#ifdef BOOST_HAS_FLOAT128 +# if __has_include() +# include +# ifndef BOOST_MP_HAS_FLOAT128_SUPPORT +# define BOOST_MP_HAS_FLOAT128_SUPPORT +# endif +# endif +#endif + #include +#include #include #include diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp index b1c5b4454..74f893a1f 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp @@ -10,10 +10,6 @@ #include -#ifdef BOOST_HAS_FLOAT128 -#include -#endif - #include #include #include diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp index ea177c495..6c01d91bd 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp @@ -15,16 +15,8 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_ namespace detail { -#if defined(BOOST_HAS_FLOAT128) template -auto floor_impl(T x) -> typename ::std::enable_if<::std::is_same::value, T>::type -{ - return ::floorq(x); -} -#endif - -template -auto floor_impl(T x) -> typename ::std::enable_if<::std::is_floating_point::value, T>::type +auto floor_impl(T x) -> T { // Default to the regular std::floor function. using std::floor; diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp index 33bb164c9..478a45e6f 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp @@ -21,7 +21,7 @@ namespace detail { template auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value, T>::type { - return ::fmaq(x); + return ::fmaq(x, y, z); } #endif @@ -45,11 +45,12 @@ auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_sam } #else template -auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_floating_point::value, T>::type +auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value || ::std::is_same::value || ::std::is_same::value, T>::type { - // Default to the written-out operations. + // Default to the written-out operations. + using std::fma; - return (x * y) + z; + return fma(x, y, z); } #endif diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp index cb648f40f..a2318788a 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp @@ -18,7 +18,7 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_df_qf_detail { namespace ccmath { template -constexpr auto fpclassify(T x) -> typename std::enable_if::value, int>::type +constexpr auto fpclassify(T x) -> int { if ((::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::isnan)(x)) { diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp index 92d9f8bca..aae8a8d2c 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp @@ -16,16 +16,8 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_ namespace detail { -#if defined(BOOST_HAS_FLOAT128) template -auto frexp_impl(T arg, int* expptr) -> typename ::std::enable_if<::std::is_same::value, T>::type -{ - return ::frexpq(arg, expptr); -} -#endif - -template -auto frexp_impl(T arg, int* expptr) -> typename ::std::enable_if<::std::is_floating_point::value, T>::type +auto frexp_impl(T arg, int* expptr) -> T { // Default to the regular std::frexp function. using std::frexp; diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp index 317d6a9ea..563393b71 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp @@ -15,16 +15,8 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_ namespace detail { -#if defined(BOOST_HAS_FLOAT128) template -auto ldexp_impl(T arg, int expval) -> typename ::std::enable_if<::std::is_same::value, T>::type -{ - return ::ldexpq(arg, expval); -} -#endif - -template -auto ldexp_impl(T arg, int expval) -> typename ::std::enable_if<::std::is_floating_point::value, T>::type +auto ldexp_impl(T arg, int expval) -> T { // Default to the regular std::ldexp function. using std::ldexp; diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp index 20c5f4c02..da914a085 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp @@ -15,16 +15,8 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_ namespace detail { -#if defined(BOOST_HAS_FLOAT128) template -auto log_impl(T x) -> typename ::std::enable_if<::std::is_same::value, T>::type -{ - return ::logq(x); -} -#endif - -template -auto log_impl(T x) -> typename ::std::enable_if<::std::is_floating_point::value, T>::type +auto log_impl(T x) -> T { // Default to the regular std::log function. using std::log; diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp index 6e1fd7fb3..7f56f4cf7 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp @@ -15,16 +15,8 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_ namespace detail { -#if defined(BOOST_HAS_FLOAT128) template -auto sqrt_impl(T x) -> typename ::std::enable_if<::std::is_same::value, T>::type -{ - return ::sqrtq(x); -} -#endif - -template -auto sqrt_impl(T x) -> typename ::std::enable_if<::std::is_floating_point::value, T>::type +auto sqrt_impl(T x) -> T { // Default to the regular std::sqrt function. using std::sqrt; From b9ff1a2c9b2df0210776cb4d5a41b8c85951642a Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Tue, 31 Dec 2024 10:29:23 +0100 Subject: [PATCH 2/4] Simplify float128 support --- .../cpp_df_qf_detail_ccmath_fabs.hpp | 2 +- .../cpp_df_qf_detail_ccmath_floor.hpp | 2 +- .../cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp | 30 +-- .../cpp_df_qf_detail_ccmath_fpclassify.hpp | 3 +- .../cpp_df_qf_detail_ccmath_frexp.hpp | 2 +- .../cpp_df_qf_detail_ccmath_isinf.hpp | 2 +- .../cpp_df_qf_detail_ccmath_isnan.hpp | 2 +- .../cpp_df_qf_detail_ccmath_ldexp.hpp | 2 +- .../cpp_df_qf_detail_ccmath_limits.hpp | 196 +++++++++--------- .../cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp | 2 +- .../cpp_df_qf_detail_ccmath_sqrt.hpp | 2 +- include/boost/multiprecision/float128.hpp | 2 + 12 files changed, 120 insertions(+), 127 deletions(-) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp index ac841ed07..8785efa16 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2023. +// Copyright Christopher Kormanyos 2023 - 2024. // 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) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp index 6c01d91bd..a03f38907 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp @@ -18,7 +18,7 @@ namespace detail { template auto floor_impl(T x) -> T { - // Default to the regular std::floor function. + // Default to the regular floor function. using std::floor; return floor(x); diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp index 478a45e6f..db69a5754 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp @@ -17,41 +17,33 @@ namespace unsafe { namespace detail { -#if defined(BOOST_HAS_FLOAT128) template -auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value, T>::type +auto fma_impl(T x, T y, T z) noexcept -> T { - return ::fmaq(x, y, z); + // Default to the regular fma function. + using std::fma; + + return fma(x, y, z); } -#endif #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER) -template -auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value, T>::type +template <> +auto fma_impl(float x, float y, float z) noexcept -> float { return __builtin_fmaf(x, y, z); } -template -auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value, T>::type +template <> +auto fma_impl(double x, double y, double z) noexcept -> double { return __builtin_fma(x, y, z); } -template -auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value, T>::type +template <> +auto fma_impl(long double x, long double y, long double z) noexcept -> long double { return __builtin_fmal(x, y, z); } -#else -template -auto fma_impl(T x, T y, T z) noexcept -> typename ::std::enable_if<::std::is_same::value || ::std::is_same::value || ::std::is_same::value, T>::type -{ - // Default to the written-out operations. - using std::fma; - - return fma(x, y, z); -} #endif } // namespace detail diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp index a2318788a..3de62126c 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp @@ -13,7 +13,6 @@ #include #include -#include namespace boost { namespace multiprecision { namespace backends { namespace cpp_df_qf_detail { namespace ccmath { @@ -36,7 +35,7 @@ constexpr auto fpclassify(T x) -> int { return FP_ZERO; } - else if ((fabs_x > 0) && (fabs_x < (boost::multiprecision::backends::cpp_df_qf_detail::ccmath::numeric_limits::min)())) + else if ((fabs_x > 0) && (fabs_x < (::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::numeric_limits::min)())) { return FP_SUBNORMAL; } diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp index aae8a8d2c..9d00da6e2 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp @@ -19,7 +19,7 @@ namespace detail template auto frexp_impl(T arg, int* expptr) -> T { - // Default to the regular std::frexp function. + // Default to the regular frexp function. using std::frexp; return frexp(arg, expptr); diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp index fcec7fe34..680de5397 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2023. +// Copyright Christopher Kormanyos 2023 - 2024. // 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) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp index 82d9ab1db..63fc3b468 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2023. +// Copyright Christopher Kormanyos 2023 - 2024. // 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) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp index 563393b71..22b91b615 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp @@ -18,7 +18,7 @@ namespace detail { template auto ldexp_impl(T arg, int expval) -> T { - // Default to the regular std::ldexp function. + // Default to the regular ldexp function. using std::ldexp; return ldexp(arg, expval); diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp index cd074edcc..ae5f4c63e 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2023. +// Copyright Christopher Kormanyos 2023 - 2024. // 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) @@ -29,44 +29,44 @@ struct numeric_limits::value)>::type> { private: - using self_type = FloatingPointType; + using float_type = FloatingPointType; public: - static constexpr bool is_specialized = std::numeric_limits::is_specialized; - static constexpr bool is_signed = std::numeric_limits::is_signed; - static constexpr bool is_integer = std::numeric_limits::is_integer; - static constexpr bool is_exact = std::numeric_limits::is_exact; - static constexpr bool is_bounded = std::numeric_limits::is_bounded; - static constexpr bool is_modulo = std::numeric_limits::is_modulo; - static constexpr bool is_iec559 = std::numeric_limits::is_iec559; - static constexpr std::float_denorm_style has_denorm = std::numeric_limits::has_denorm; - static constexpr bool has_infinity = std::numeric_limits::has_infinity; - static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; - static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; - static constexpr bool has_denorm_loss = std::numeric_limits::has_denorm_loss; - static constexpr bool traps = std::numeric_limits::traps; - static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; - static constexpr std::float_round_style round_style = std::numeric_limits::round_style; - - static constexpr int radix = std::numeric_limits::radix; - static constexpr int digits = std::numeric_limits::digits; - static constexpr int digits10 = std::numeric_limits::digits10; - static constexpr int max_digits10 = std::numeric_limits::max_digits10; - - static constexpr int max_exponent = std::numeric_limits::max_exponent; - static constexpr int min_exponent = std::numeric_limits::min_exponent; - static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; - static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; - - static constexpr self_type(min) () noexcept { return (std::numeric_limits::min) (); } - static constexpr self_type(max) () noexcept { return (std::numeric_limits::max) (); } - static constexpr self_type lowest () noexcept { return std::numeric_limits::lowest (); } - static constexpr self_type epsilon () noexcept { return std::numeric_limits::epsilon (); } - static constexpr self_type round_error () noexcept { return std::numeric_limits::round_error (); } - static constexpr self_type denorm_min () noexcept { return std::numeric_limits::denorm_min (); } - static constexpr self_type infinity () noexcept { return std::numeric_limits::infinity (); } - static constexpr self_type quiet_NaN () noexcept { return std::numeric_limits::quiet_NaN (); } - static constexpr self_type signaling_NaN() noexcept { return std::numeric_limits::signaling_NaN(); } + static constexpr bool is_specialized = std::numeric_limits::is_specialized; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_exact = std::numeric_limits::is_exact; + static constexpr bool is_bounded = std::numeric_limits::is_bounded; + static constexpr bool is_modulo = std::numeric_limits::is_modulo; + static constexpr bool is_iec559 = std::numeric_limits::is_iec559; + static constexpr std::float_denorm_style has_denorm = std::numeric_limits::has_denorm; + static constexpr bool has_infinity = std::numeric_limits::has_infinity; + static constexpr bool has_quiet_NaN = std::numeric_limits::has_quiet_NaN; + static constexpr bool has_signaling_NaN = std::numeric_limits::has_signaling_NaN; + static constexpr bool has_denorm_loss = std::numeric_limits::has_denorm_loss; + static constexpr bool traps = std::numeric_limits::traps; + static constexpr bool tinyness_before = std::numeric_limits::tinyness_before; + static constexpr std::float_round_style round_style = std::numeric_limits::round_style; + + static constexpr int radix = std::numeric_limits::radix; + static constexpr int digits = std::numeric_limits::digits; + static constexpr int digits10 = std::numeric_limits::digits10; + static constexpr int max_digits10 = std::numeric_limits::max_digits10; + + static constexpr int max_exponent = std::numeric_limits::max_exponent; + static constexpr int min_exponent = std::numeric_limits::min_exponent; + static constexpr int max_exponent10 = std::numeric_limits::max_exponent10; + static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; + + static constexpr float_type(min) () noexcept { return (std::numeric_limits::min) (); } + static constexpr float_type(max) () noexcept { return (std::numeric_limits::max) (); } + static constexpr float_type lowest () noexcept { return std::numeric_limits::lowest (); } + static constexpr float_type epsilon () noexcept { return std::numeric_limits::epsilon (); } + static constexpr float_type round_error () noexcept { return std::numeric_limits::round_error (); } + static constexpr float_type denorm_min () noexcept { return std::numeric_limits::denorm_min (); } + static constexpr float_type infinity () noexcept { return std::numeric_limits::infinity (); } + static constexpr float_type quiet_NaN () noexcept { return std::numeric_limits::quiet_NaN (); } + static constexpr float_type signaling_NaN() noexcept { return std::numeric_limits::signaling_NaN(); } }; #if defined(BOOST_HAS_FLOAT128) @@ -75,7 +75,7 @@ struct numeric_limits::value>::type> { private: - using self_type = ::boost::float128_type; + using float_type = ::boost::float128_type; public: static constexpr bool is_specialized = true; @@ -104,86 +104,86 @@ struct numeric_limits(static_cast(static_cast(max_exponent) * 301LL) / 1000LL); static constexpr int min_exponent10 = static_cast(static_cast(static_cast(min_exponent) * 301LL) / 1000LL); - static constexpr self_type (min)() noexcept + static constexpr float_type (min)() noexcept { - return static_cast(1) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) / 1073741824; + return static_cast(1) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) / 1073741824; } - static constexpr self_type (max)() noexcept + static constexpr float_type (max)() noexcept { // This has one bit set only. constexpr double dbl_mult = 8.9884656743115795386e+307; - return (static_cast(1) - 9.62964972193617926527988971292463659e-35) // This now has all bits sets to 1 - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) * 65536; + return (static_cast(1) - 9.62964972193617926527988971292463659e-35) // This now has all bits sets to 1 + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) + * static_cast(dbl_mult) * 65536; } - static constexpr self_type lowest() noexcept { return -(max)(); } + static constexpr float_type lowest() noexcept { return -(max)(); } - static constexpr self_type epsilon() + static constexpr float_type epsilon() { // This double value has only one bit set and so is exact. return 1.92592994438723585305597794258492732e-34; } - static constexpr self_type round_error() noexcept { return 0.5; } + static constexpr float_type round_error() noexcept { return 0.5; } - static constexpr self_type denorm_min() noexcept + static constexpr float_type denorm_min() noexcept { - return static_cast(1) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) + return static_cast(1) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) + * static_cast(DBL_MIN) / 5.5751862996326557854e+42; } - static constexpr self_type infinity () noexcept { return HUGE_VAL; } - static constexpr self_type quiet_NaN () noexcept { return NAN; } - static constexpr self_type signaling_NaN() noexcept { return 0; } + static constexpr float_type infinity () noexcept { return HUGE_VAL; } + static constexpr float_type quiet_NaN () noexcept { return NAN; } + static constexpr float_type signaling_NaN() noexcept { return 0; } }; #endif diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp index da914a085..828e51aad 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp @@ -18,7 +18,7 @@ namespace detail { template auto log_impl(T x) -> T { - // Default to the regular std::log function. + // Default to the regular log function. using std::log; return log(x); diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp index 7f56f4cf7..044ae53ab 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp @@ -18,7 +18,7 @@ namespace detail { template auto sqrt_impl(T x) -> T { - // Default to the regular std::sqrt function. + // Default to the regular sqrt function. using std::sqrt; return sqrt(x); diff --git a/include/boost/multiprecision/float128.hpp b/include/boost/multiprecision/float128.hpp index 83f5f11f9..7fda95314 100644 --- a/include/boost/multiprecision/float128.hpp +++ b/include/boost/multiprecision/float128.hpp @@ -67,6 +67,7 @@ _Quad __ldexpq(_Quad, int); _Quad __frexpq(_Quad, int*); _Quad __fabsq(_Quad); _Quad __floorq(_Quad); +_Quad __fmaq(_Quad, _Quad, _Quad); _Quad __ceilq(_Quad); _Quad __sqrtq(_Quad); _Quad __truncq(_Quad); @@ -90,6 +91,7 @@ _Quad __atan2q(_Quad, _Quad); #define frexpq __frexpq #define fabsq __fabsq #define floorq __floorq +#define fmaq __fmaq #define ceilq __ceilq #define sqrtq __sqrtq #define truncq __truncq From e361071c504ad0cbb5b01eef7d642a4aa07c1fc9 Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Tue, 31 Dec 2024 13:53:12 +0100 Subject: [PATCH 3/4] More tuning and try repair CI --- .../cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp | 9 +- .../cpp_df_qf_detail_ccmath_limits.hpp | 142 ++---------------- .../boost/multiprecision/cpp_double_fp.hpp | 106 ++++++------- include/boost/multiprecision/float128.hpp | 2 - test/test_exp.cpp | 12 +- test/test_log.cpp | 2 +- 6 files changed, 68 insertions(+), 205 deletions(-) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp index db69a5754..cb87b2d1f 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp @@ -18,12 +18,11 @@ namespace unsafe { namespace detail { template -auto fma_impl(T x, T y, T z) noexcept -> T +constexpr auto fma_impl(T x, T y, T z) noexcept -> T { - // Default to the regular fma function. - using std::fma; + // Default to the written-out operations. - return fma(x, y, z); + return (x * y) + z; } #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER) @@ -49,7 +48,7 @@ auto fma_impl(long double x, long double y, long double z) noexcept } // namespace detail template -auto fma(Real x, Real y, Real z) noexcept -> Real +constexpr auto fma(Real x, Real y, Real z) noexcept -> Real { return detail::fma_impl(x, y, z); } diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp index ae5f4c63e..e6dbbc321 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp @@ -26,7 +26,11 @@ template struct numeric_limits::value || std::is_same::value - || std::is_same::value)>::type> + || std::is_same::value +#if defined(BOOST_HAS_FLOAT128) + || std::is_same::value +#endif + )>::type> { private: using float_type = FloatingPointType; @@ -58,134 +62,16 @@ struct numeric_limits::max_exponent10; static constexpr int min_exponent10 = std::numeric_limits::min_exponent10; - static constexpr float_type(min) () noexcept { return (std::numeric_limits::min) (); } - static constexpr float_type(max) () noexcept { return (std::numeric_limits::max) (); } - static constexpr float_type lowest () noexcept { return std::numeric_limits::lowest (); } - static constexpr float_type epsilon () noexcept { return std::numeric_limits::epsilon (); } - static constexpr float_type round_error () noexcept { return std::numeric_limits::round_error (); } - static constexpr float_type denorm_min () noexcept { return std::numeric_limits::denorm_min (); } - static constexpr float_type infinity () noexcept { return std::numeric_limits::infinity (); } - static constexpr float_type quiet_NaN () noexcept { return std::numeric_limits::quiet_NaN (); } - static constexpr float_type signaling_NaN() noexcept { return std::numeric_limits::signaling_NaN(); } -}; - -#if defined(BOOST_HAS_FLOAT128) -template -struct numeric_limits::value>::type> -{ -private: - using float_type = ::boost::float128_type; - -public: - static constexpr bool is_specialized = true; - static constexpr bool is_signed = true; - static constexpr bool is_integer = false; - static constexpr bool is_exact = false; - static constexpr bool is_bounded = true; - static constexpr bool is_modulo = false; - static constexpr bool is_iec559 = true; - static constexpr std::float_denorm_style has_denorm = std::denorm_present; - static constexpr bool has_infinity = true; - static constexpr bool has_quiet_NaN = true; - static constexpr bool has_signaling_NaN = false; - static constexpr bool has_denorm_loss = true; - static constexpr bool traps = false; - static constexpr bool tinyness_before = false; - static constexpr std::float_round_style round_style = std::round_to_nearest; - - static constexpr int radix = 2; - static constexpr int digits = 113; - static constexpr int digits10 = 33; - static constexpr int max_digits10 = 36; - - static constexpr int max_exponent = 16384; - static constexpr int min_exponent = -16381; - static constexpr int max_exponent10 = static_cast(static_cast(static_cast(max_exponent) * 301LL) / 1000LL); - static constexpr int min_exponent10 = static_cast(static_cast(static_cast(min_exponent) * 301LL) / 1000LL); - - static constexpr float_type (min)() noexcept - { - return static_cast(1) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) / 1073741824; - } - - static constexpr float_type (max)() noexcept - { - // This has one bit set only. - constexpr double dbl_mult = 8.9884656743115795386e+307; - - return (static_cast(1) - 9.62964972193617926527988971292463659e-35) // This now has all bits sets to 1 - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) - * static_cast(dbl_mult) * 65536; - } - - static constexpr float_type lowest() noexcept { return -(max)(); } - - static constexpr float_type epsilon() - { - // This double value has only one bit set and so is exact. - return 1.92592994438723585305597794258492732e-34; - } - - static constexpr float_type round_error() noexcept { return 0.5; } - - static constexpr float_type denorm_min() noexcept - { - return static_cast(1) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - * static_cast(DBL_MIN) - / 5.5751862996326557854e+42; - } - - static constexpr float_type infinity () noexcept { return HUGE_VAL; } - static constexpr float_type quiet_NaN () noexcept { return NAN; } - static constexpr float_type signaling_NaN() noexcept { return 0; } + static constexpr auto (min) () noexcept -> float_type { return (std::numeric_limits::min) (); } + static constexpr auto (max) () noexcept -> float_type { return (std::numeric_limits::max) (); } + static constexpr auto lowest () noexcept -> float_type { return std::numeric_limits::lowest (); } + static constexpr auto epsilon () noexcept -> float_type { return std::numeric_limits::epsilon (); } + static constexpr auto round_error () noexcept -> float_type { return std::numeric_limits::round_error (); } + static constexpr auto denorm_min () noexcept -> float_type { return std::numeric_limits::denorm_min (); } + static constexpr auto infinity () noexcept -> float_type { return std::numeric_limits::infinity (); } + static constexpr auto quiet_NaN () noexcept -> float_type { return std::numeric_limits::quiet_NaN (); } + static constexpr auto signaling_NaN() noexcept -> float_type { return std::numeric_limits::signaling_NaN(); } }; -#endif } } } } } // namespace boost::backends::cpp_df_qf_detail::ccmath diff --git a/include/boost/multiprecision/cpp_double_fp.hpp b/include/boost/multiprecision/cpp_double_fp.hpp index e87f24821..0785fd4a8 100644 --- a/include/boost/multiprecision/cpp_double_fp.hpp +++ b/include/boost/multiprecision/cpp_double_fp.hpp @@ -225,6 +225,7 @@ class cpp_double_fp_backend // TBD: Need to keep widening conversion implicit, // but ensure that narrowing conversion is explicit. + template ::value && (!std::is_same::value))>::type const* = nullptr> @@ -345,6 +346,7 @@ class cpp_double_fp_backend { // Here we first convert to scientific string, then // hash the charactgers in the scientific string. + // TBD: Is there a faster or more simple hash method? // TBD: Is there any constexpr support for rudimentary hashing? @@ -365,7 +367,6 @@ class cpp_double_fp_backend constexpr bool is_zero() const noexcept { - #if 1 using local_backend_type = cpp_double_fp_backend; using local_float_type = typename local_backend_type::float_type; @@ -374,9 +375,6 @@ class cpp_double_fp_backend ((data.first == local_float_type { 0 }) || (-data.first == local_float_type { 0 })) && ((data.second == local_float_type { 0 }) || (-data.second == local_float_type { 0 })) ); - #else - return (compare(cpp_double_fp_backend(0U)) == 0); - #endif } constexpr bool is_one() const noexcept @@ -389,17 +387,10 @@ class cpp_double_fp_backend constexpr void negate() { - // TBD: Can this be simplified? - - const auto fpc = eval_fpclassify(*this); + const bool isinf_u { (cpp_df_qf_detail::ccmath::isinf)(data.first) }; + const bool isnan_u { (cpp_df_qf_detail::ccmath::isnan)(data.first) }; - const auto isinf_u = (fpc == FP_INFINITE); - const auto isnan_u = (fpc == FP_NAN); - const auto iszero_u = (fpc == FP_ZERO); - - if (iszero_u || isnan_u) - { - } + if (isnan_u) { } else if (isinf_u) { data.first = -data.first; @@ -416,7 +407,9 @@ class cpp_double_fp_backend constexpr bool isneg() const noexcept { - return (data.first < 0); + const bool isnan_u { (cpp_df_qf_detail::ccmath::isnan)(data.first) }; + + return ((!isnan_u) && (data.first < 0)); } // Getters/Setters @@ -1503,40 +1496,33 @@ constexpr void eval_sqrt(cpp_double_fp_backend& result, const } } - // TBD: Optimize this in a similar was as has been done for mul/div. + // TBD: Do we need any overflow/underflow guards when multiplying + // by the split or when multiplying (hx * tx) and/or (hx * hx)? + + const local_float_type c { cpp_df_qf_detail::ccmath::sqrt(o.crep().first) }; - // TBD: Taking the square root of a large number (like the (max)() value) - // will overflow when multiplying by the split. Can this be handled - // more graciously? + local_float_type p { cpp_df_qf_detail::split_maker::value * c }; - const local_float_type c = cpp_df_qf_detail::ccmath::sqrt(o.crep().first); + const local_float_type hx { (c - p) + p }; + const local_float_type tx { c - hx }; - local_float_type p = cpp_df_qf_detail::split_maker::value * c; - local_float_type hx = (c - p); - hx = hx + p; - local_float_type tx = c - hx; - p = hx * hx; local_float_type q = hx * tx; - q = q + q; - - local_float_type u = p + q; - local_float_type uu = p - u; - uu = uu + q; - local_float_type t1 = tx * tx; - uu = uu + t1; - - local_float_type cc = o.crep().first - u; - cc = cc - uu; - cc = cc + o.crep().second; - t1 = c + c; - cc = cc / t1; - - hx = c + cc; - tx = c - hx; - tx = tx + cc; - - result.rep().first = hx; - result.rep().second = tx; + q = q + q; + + p = hx * hx; + + const local_float_type u { p + q }; + + const local_float_type uu { cpp_df_qf_detail::ccmath::unsafe::fma(tx, tx, local_float_type { p - u } + q) }; + + const local_float_type + cc + { + local_float_type { local_float_type { o.crep().first - u } - uu + o.crep().second } / local_float_type { c + c } + }; + + result.rep().first = c + cc; + result.rep().second = local_float_type { c - result.rep().first } + cc; } template & result, const using local_float_type = typename double_float_type::float_type; // Get a local copy of the argument and force it to be positive. - const auto b_neg = x.is_neg(); - - double_float_type xx { }; + const bool b_neg { x.is_neg() }; - eval_fabs(xx, x); + const double_float_type xx { (!b_neg) ? x : -x }; // Check the range of the input. const double_float_type max_exp_input @@ -1725,11 +1709,9 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const using local_float_type = typename double_float_type::float_type; // Get a local copy of the argument and force it to be positive. - const auto b_neg = x.is_neg(); + const bool b_neg { x.is_neg() }; - double_float_type xx { }; - - eval_fabs(xx, x); + const double_float_type xx { (!b_neg) ? x : -x }; // Check the range of the input. const double_float_type max_exp_input @@ -1881,11 +1863,9 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const using local_float_type = typename double_float_type::float_type; // Get a local copy of the argument and force it to be positive. - const auto b_neg = x.is_neg(); - - double_float_type xx { }; + const bool b_neg { x.is_neg() }; - eval_fabs(xx, x); + const double_float_type xx { (!b_neg) ? x : -x }; // Check the range of the input. const double_float_type max_exp_input @@ -2014,19 +1994,17 @@ constexpr void eval_log(cpp_double_fp_backend& result, const { using double_float_type = cpp_double_fp_backend; - const auto fpc = eval_fpclassify(x); - - const auto x_is_zero = (fpc == FP_ZERO); + const int fpc { eval_fpclassify(x) }; - if ((fpc != FP_NORMAL) && (!x_is_zero)) + if (fpc == FP_ZERO) { - result = x; + result = -double_float_type::my_value_inf(); } - else if (x.is_neg()) + else if (x.is_neg() || (fpc == FP_NAN)) { result = double_float_type::my_value_nan(); } - else if (x_is_zero) + else if (fpc == FP_INFINITE) { result = double_float_type::my_value_inf(); } diff --git a/include/boost/multiprecision/float128.hpp b/include/boost/multiprecision/float128.hpp index 7fda95314..83f5f11f9 100644 --- a/include/boost/multiprecision/float128.hpp +++ b/include/boost/multiprecision/float128.hpp @@ -67,7 +67,6 @@ _Quad __ldexpq(_Quad, int); _Quad __frexpq(_Quad, int*); _Quad __fabsq(_Quad); _Quad __floorq(_Quad); -_Quad __fmaq(_Quad, _Quad, _Quad); _Quad __ceilq(_Quad); _Quad __sqrtq(_Quad); _Quad __truncq(_Quad); @@ -91,7 +90,6 @@ _Quad __atan2q(_Quad, _Quad); #define frexpq __frexpq #define fabsq __fabsq #define floorq __floorq -#define fmaq __fmaq #define ceilq __ceilq #define sqrtq __sqrtq #define truncq __truncq diff --git a/test/test_exp.cpp b/test/test_exp.cpp index 7bebc2c60..11328b319 100644 --- a/test/test_exp.cpp +++ b/test/test_exp.cpp @@ -210,14 +210,16 @@ void test() } } - bug_case = log((std::numeric_limits::max)()) / -1.0005; - unsigned i { 0U }; #if defined(TEST_CPP_DOUBLE_FLOAT) - BOOST_IF_CONSTEXPR(std::is_same::value) { for ( ; i < 7; ++i, bug_case /= 1.05) { ; } } - BOOST_IF_CONSTEXPR(std::is_same::value) { for ( ; i < 3; ++i, bug_case /= 1.05) { ; } } - BOOST_IF_CONSTEXPR(std::is_same::value) { for ( ; i < 3; ++i, bug_case /= 1.05) { ; } } + // Handle uneven/asymmetric exponents on min/max of cpp_double_fp_backend + bug_case = log(1 / (std::numeric_limits::min)()) / -1.0005; + #else + bug_case = log((std::numeric_limits::max)()) / -1.0005; #endif + + unsigned i { 0U }; + for ( ; i < 20U; ++i, bug_case /= static_cast(1.05L)) { BOOST_CHECK_GE(exp(bug_case), (std::numeric_limits::min)()); diff --git a/test/test_log.cpp b/test/test_log.cpp index 0e9a6c20b..42b8d9110 100644 --- a/test/test_log.cpp +++ b/test/test_log.cpp @@ -265,7 +265,7 @@ int main() #ifdef TEST_CPP_DOUBLE_FLOAT test(); test(); - //test(); + test(); #if defined(BOOST_HAS_FLOAT128) test(); #endif From 06f2892388f2319395d1770a8059b7348ab85530 Mon Sep 17 00:00:00 2001 From: ckormanyos Date: Tue, 31 Dec 2024 14:32:14 +0100 Subject: [PATCH 4/4] Correct syntax of fma_impl specializations --- .../cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp index cb87b2d1f..c5059e7e8 100644 --- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp +++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp @@ -18,7 +18,7 @@ namespace unsafe { namespace detail { template -constexpr auto fma_impl(T x, T y, T z) noexcept -> T +inline auto fma_impl(T x, T y, T z) noexcept -> T { // Default to the written-out operations. @@ -27,19 +27,19 @@ constexpr auto fma_impl(T x, T y, T z) noexcept -> T #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER) template <> -auto fma_impl(float x, float y, float z) noexcept -> float +inline auto fma_impl(float x, float y, float z) noexcept -> float { return __builtin_fmaf(x, y, z); } template <> -auto fma_impl(double x, double y, double z) noexcept -> double +inline auto fma_impl(double x, double y, double z) noexcept -> double { return __builtin_fma(x, y, z); } template <> -auto fma_impl(long double x, long double y, long double z) noexcept -> long double +inline auto fma_impl(long double x, long double y, long double z) noexcept -> long double { return __builtin_fmal(x, y, z); } @@ -48,7 +48,7 @@ auto fma_impl(long double x, long double y, long double z) noexcept } // namespace detail template -constexpr auto fma(Real x, Real y, Real z) noexcept -> Real +auto fma(Real x, Real y, Real z) noexcept -> Real { return detail::fma_impl(x, y, z); }