From a3c8d7fbe29d4ab60cc46196a1376854734a4f8d Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 24 Jun 2019 13:09:51 +0100 Subject: [PATCH] Fix std::midpoint for denormal values * include/std/numeric (midpoint(T, T)): Change implementation for floating-point types to avoid incorrect rounding of denormals. * testsuite/26_numerics/midpoint/floating.cc: Add check for correct rounding with denormals. * testsuite/26_numerics/gcd/gcd_neg.cc: Adjust dg-error line numbers. * testsuite/26_numerics/lcm/lcm_neg.cc: Likewise. From-SVN: r272616 --- libstdc++-v3/ChangeLog | 7 ++++ libstdc++-v3/include/std/numeric | 36 +++++++++++++------ .../testsuite/26_numerics/gcd/gcd_neg.cc | 6 ++-- .../testsuite/26_numerics/lcm/lcm_neg.cc | 6 ++-- .../26_numerics/midpoint/floating.cc | 14 ++++++++ 5 files changed, 52 insertions(+), 17 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2acb1508978..35c79f93389 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,12 @@ 2019-06-24 Jonathan Wakely + * include/std/numeric (midpoint(T, T)): Change implementation for + floating-point types to avoid incorrect rounding of denormals. + * testsuite/26_numerics/midpoint/floating.cc: Add check for correct + rounding with denormals. + * testsuite/26_numerics/gcd/gcd_neg.cc: Adjust dg-error line numbers. + * testsuite/26_numerics/lcm/lcm_neg.cc: Likewise. + * testsuite/18_support/headers/cfloat/values_c++17.cc: New test. 2019-06-20 Jonathan Wakely diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric index fc2242f3de6..af684469769 100644 --- a/libstdc++-v3/include/std/numeric +++ b/libstdc++-v3/include/std/numeric @@ -69,9 +69,8 @@ * @defgroup numerics Numerics * * Components for performing numeric operations. Includes support for - * for complex number types, random number generation, numeric - * (n-at-a-time) arrays, generalized numeric algorithms, and special - * math functions. + * complex number types, random number generation, numeric (n-at-a-time) + * arrays, generalized numeric algorithms, and mathematical special functions. */ #if __cplusplus >= 201402L @@ -156,11 +155,22 @@ namespace __detail #endif // C++17 +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++14 + #if __cplusplus > 201703L +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION // midpoint # define __cpp_lib_interpolate 201902L -template + template constexpr enable_if_t<__and_v, is_same, _Tp>, __not_>>, @@ -182,11 +192,17 @@ template } return __a + __k * _Tp(_Up(__M - __m) / 2); } - else + else // is_floating { - return __builtin_isnormal(__a) && __builtin_isnormal(__b) - ? __a / 2 + __b / 2 - : (__a + __b) / 2; + constexpr _Tp __lo = numeric_limits<_Tp>::min() * 2; + constexpr _Tp __hi = numeric_limits<_Tp>::max() / 2; + if (std::abs(__a) <= __hi && std::abs(__b) <= __hi) [[likely]] + return (__a + __b) / 2; // always correctly rounded + if (std::abs(__a) < __lo) // not safe to halve __a + return __a + __b/2; + if (std::abs(__b) < __lo) // not safe to halve __b + return __a/2 + __b; + return __a/2 + __b/2; // otherwise correctly rounded } } @@ -197,12 +213,10 @@ template { return __a + (__b - __a) / 2; } -#endif // C++20 - _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++14 +#endif // C++20 #if __cplusplus > 201402L #include diff --git a/libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc b/libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc index 87a74988fa4..05e21431313 100644 --- a/libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc +++ b/libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc @@ -46,9 +46,9 @@ test01() std::gcd(0.1, 0.1); // { dg-error "from here" } } +// { dg-error "integers" "" { target *-*-* } 133 } // { dg-error "integers" "" { target *-*-* } 134 } -// { dg-error "integers" "" { target *-*-* } 135 } -// { dg-error "not bools" "" { target *-*-* } 136 } -// { dg-error "not bools" "" { target *-*-* } 138 } +// { dg-error "not bools" "" { target *-*-* } 135 } +// { dg-error "not bools" "" { target *-*-* } 137 } // { dg-prune-output "deleted function" } // { dg-prune-output "invalid operands" } diff --git a/libstdc++-v3/testsuite/26_numerics/lcm/lcm_neg.cc b/libstdc++-v3/testsuite/26_numerics/lcm/lcm_neg.cc index 4db01ae3647..3a0f5bbe3eb 100644 --- a/libstdc++-v3/testsuite/26_numerics/lcm/lcm_neg.cc +++ b/libstdc++-v3/testsuite/26_numerics/lcm/lcm_neg.cc @@ -46,9 +46,9 @@ test01() std::lcm(0.1, 0.1); // { dg-error "from here" } } +// { dg-error "integers" "" { target *-*-* } 147 } // { dg-error "integers" "" { target *-*-* } 148 } -// { dg-error "integers" "" { target *-*-* } 149 } -// { dg-error "not bools" "" { target *-*-* } 150 } -// { dg-error "not bools" "" { target *-*-* } 152 } +// { dg-error "not bools" "" { target *-*-* } 149 } +// { dg-error "not bools" "" { target *-*-* } 151 } // { dg-prune-output "deleted function" } // { dg-prune-output "invalid operands" } diff --git a/libstdc++-v3/testsuite/26_numerics/midpoint/floating.cc b/libstdc++-v3/testsuite/26_numerics/midpoint/floating.cc index 9c6e4113b18..32a966e2c63 100644 --- a/libstdc++-v3/testsuite/26_numerics/midpoint/floating.cc +++ b/libstdc++-v3/testsuite/26_numerics/midpoint/floating.cc @@ -20,6 +20,7 @@ #include #include +#include #include void @@ -57,6 +58,19 @@ test03() VERIFY( std::midpoint(9e9l, -9e9l) == 0.0l ); } +namespace test04 +{ + // https://gcc.gnu.org/ml/libstdc++/2019-03/msg00065.html + constexpr double d = DBL_MIN + DBL_TRUE_MIN; + static_assert( std::midpoint(d, d) == d ); + + constexpr float f = FLT_MIN + FLT_TRUE_MIN; + static_assert( std::midpoint(f, f) == f ); + + constexpr long double l = LDBL_MIN + LDBL_TRUE_MIN; + static_assert( std::midpoint(l, l) == l ); +} + int main() { test01(); -- 2.30.2