[gcc/devel/omp/gcc-9] Fix std::midpoint for denormal values

Tobias Burnus burnus@gcc.gnu.org
Thu Mar 5 14:11:00 GMT 2020


https://gcc.gnu.org/g:7b9f874f9ad400b3420a4cd3e029a5d86932641f

commit 7b9f874f9ad400b3420a4cd3e029a5d86932641f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Jul 26 14:36:25 2019 +0100

    Fix std::midpoint for denormal values
    
    Backport from mainline
    2019-06-25  Jonathan Wakely  <jwakely@redhat.com>
    
    	* include/std/numeric (midpoint(T, T)): Avoid std::abs in constexpr
    	function.
    
    Backport from mainline
    2019-06-24  Jonathan Wakely  <jwakely@redhat.com>
    
    	* 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: r273829

Diff:
---
 libstdc++-v3/ChangeLog                             | 18 +++++++++++
 libstdc++-v3/include/std/numeric                   | 37 +++++++++++++++-------
 libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc  |  6 ++--
 libstdc++-v3/testsuite/26_numerics/lcm/lcm_neg.cc  |  6 ++--
 .../testsuite/26_numerics/midpoint/floating.cc     | 14 ++++++++
 5 files changed, 64 insertions(+), 17 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index c75886d..de7b156 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,21 @@
+2019-07-26  Jonathan Wakely  <jwakely@redhat.com>
+
+	Backport from mainline
+	2019-06-25  Jonathan Wakely  <jwakely@redhat.com>
+
+	* include/std/numeric (midpoint(T, T)): Avoid std::abs in constexpr
+	function.
+
+	Backport from mainline
+	2019-06-24  Jonathan Wakely  <jwakely@redhat.com>
+
+	* 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.
+
 2019-07-03  Jonathan Wakely  <jwakely@redhat.com>
 
 	PR libstdc++/91067
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index 3babfaa..bef823b 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,21 @@ namespace __detail
 
 #endif // C++17
 
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++14
+
 #if __cplusplus > 201703L
+#include <limits>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
   // midpoint
 # define __cpp_lib_interpolate 201902L
 
-template<typename _Tp>
+  template<typename _Tp>
     constexpr
     enable_if_t<__and_v<is_arithmetic<_Tp>, is_same<remove_cv_t<_Tp>, _Tp>,
 			__not_<is_same<_Tp, bool>>>,
@@ -182,11 +191,19 @@ template<typename _Tp>
 	    }
 	  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;
+	  const _Tp __abs_a = __a < 0 ? -__a : __a;
+	  const _Tp __abs_b = __b < 0 ? -__b : __b;
+	  if (__abs_a <= __hi && __abs_b <= __hi) [[likely]]
+	    return (__a + __b) / 2; // always correctly rounded
+	  if (__abs_a < __lo) // not safe to halve __a
+	    return __a + __b/2;
+	  if (__abs_b < __lo) // not safe to halve __b
+	    return __a/2 + __b;
+	  return __a/2 + __b/2;	    // otherwise correctly rounded
 	}
     }
 
@@ -197,12 +214,10 @@ template<typename _Tp>
     {
       return __a  + (__b - __a) / 2;
     }
-#endif // C++20
-
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
-#endif // C++14
+#endif // C++20
 
 #if __cplusplus > 201402L
 // Parallel STL algorithms
diff --git a/libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc b/libstdc++-v3/testsuite/26_numerics/gcd/gcd_neg.cc
index 87a7498..05e2143 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<const int&, const int&>(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 4db01ae..3a0f5bb 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<const int&, const int&>(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 9c6e411..f09f586 100644
--- a/libstdc++-v3/testsuite/26_numerics/midpoint/floating.cc
+++ b/libstdc++-v3/testsuite/26_numerics/midpoint/floating.cc
@@ -20,6 +20,7 @@
 
 #include <numeric>
 #include <limits>
+#include <cfloat>
 #include <testsuite_hooks.h>
 
 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_DENORM_MIN__;
+  static_assert( std::midpoint(d, d) == d );
+
+  constexpr float f = FLT_MIN + __FLT_DENORM_MIN__;
+  static_assert( std::midpoint(f, f) == f );
+
+  constexpr long double l = LDBL_MIN + __LDBL_DENORM_MIN__;
+  static_assert( std::midpoint(l, l) == l );
+}
+
 int main()
 {
   test01();



More information about the Gcc-cvs mailing list