[libcxx-commits] [libcxx] [libcxx][test][z/OS] Fix hermite.pass.cpp for HEX float (PR #101019)

Zibi Sarbinowski via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 2 13:32:51 PDT 2024


https://github.com/zibi2 updated https://github.com/llvm/llvm-project/pull/101019

>From 5df433b4ea5e657079e5d5e7305dc06b0331beeb Mon Sep 17 00:00:00 2001
From: Zbigniew Sarbinowski <zibi at ca.ibm.com>
Date: Mon, 29 Jul 2024 14:01:36 +0000
Subject: [PATCH 1/5] Fix hermite.pass.cpp for HEX float on z/OS

---
 libcxx/test/std/numerics/c.math/hermite.pass.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
index 08fbd5c3283c1..fb702369ad036 100644
--- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
@@ -26,7 +26,12 @@
 
 #include "type_algorithms.h"
 
-inline constexpr unsigned g_max_n = 128;
+inline constexpr unsigned g_max_n =
+#if !(defined(__MVS__) && !defined(__BFP__))
+  128;
+#else
+  39;
+#endif
 
 template <class T>
 std::array<T, 11> sample_points() {
@@ -203,6 +208,7 @@ std::vector<T> get_roots(unsigned n) {
 
 template <class Real>
 void test() {
+#if !(defined(__MVS__) && !defined(__BFP__))
   { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
     using nl = std::numeric_limits<Real>;
     for (Real NaN : {nl::quiet_NaN(), nl::signaling_NaN()})
@@ -215,6 +221,7 @@ void test() {
       for (unsigned n = 0; n < g_max_n; ++n)
         assert(!std::isnan(std::hermite(n, x)));
   }
+#endif
 
   { // checks std::hermite(n, x) for n=0..5 against analytic polynoms
     const auto h0 = [](Real) -> Real { return 1; };
@@ -289,6 +296,7 @@ void test() {
     }
   }
 
+#if !(defined(__MVS__) && !defined(__BFP__))
   { // check input infinity is handled correctly
     Real inf = std::numeric_limits<Real>::infinity();
     for (unsigned n = 1; n < g_max_n; ++n) {
@@ -316,6 +324,7 @@ void test() {
       }
     }
   }
+#endif
 }
 
 struct TestFloat {

>From 75025ad1b8fd35537bd3fa5e862fefe76b2fd446 Mon Sep 17 00:00:00 2001
From: Zbigniew Sarbinowski <zibi at ca.ibm.com>
Date: Mon, 29 Jul 2024 14:51:25 +0000
Subject: [PATCH 2/5] clang-format change

---
 libcxx/test/std/numerics/c.math/hermite.pass.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
index fb702369ad036..2da2b0b5224af 100644
--- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
@@ -28,9 +28,9 @@
 
 inline constexpr unsigned g_max_n =
 #if !(defined(__MVS__) && !defined(__BFP__))
-  128;
+    128;
 #else
-  39;
+    39;
 #endif
 
 template <class T>

>From b4ece9122d33080c511dd44aca053d41d2c3ad9c Mon Sep 17 00:00:00 2001
From: Zbigniew Sarbinowski <zibi at ca.ibm.com>
Date: Wed, 31 Jul 2024 21:35:10 +0000
Subject: [PATCH 3/5] eliminating #if directives and code formatting

---
 .../test/std/numerics/c.math/hermite.pass.cpp | 49 ++++++++++---------
 1 file changed, 26 insertions(+), 23 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
index 2da2b0b5224af..28bf27cafc3dd 100644
--- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
@@ -26,12 +26,13 @@
 
 #include "type_algorithms.h"
 
-inline constexpr unsigned g_max_n =
-#if !(defined(__MVS__) && !defined(__BFP__))
-    128;
-#else
-    39;
-#endif
+template <class Real>
+constexpr unsigned get_maximal_order() {
+  if constexpr (std::numeric_limits<Real>::max_exponent10 < std::numeric_limits<Real>::max_exponent)
+    return 128;
+  else
+    return 39;
+}
 
 template <class T>
 std::array<T, 11> sample_points() {
@@ -208,20 +209,23 @@ std::vector<T> get_roots(unsigned n) {
 
 template <class Real>
 void test() {
-#if !(defined(__MVS__) && !defined(__BFP__))
-  { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
+  if constexpr (
+      std::numeric_limits<Real>::has_quiet_NaN &&
+      std::numeric_limits<
+          Real>::has_signaling_NaN) { // checks if NaNs are reported correctly (i.e. output == input for input == NaN)
     using nl = std::numeric_limits<Real>;
     for (Real NaN : {nl::quiet_NaN(), nl::signaling_NaN()})
-      for (unsigned n = 0; n < g_max_n; ++n)
+      for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
         assert(std::isnan(std::hermite(n, NaN)));
   }
 
-  { // simple sample points for n=0..127 should not produce NaNs.
+  if constexpr (std::numeric_limits<Real>::has_quiet_NaN &&
+                std::numeric_limits<
+                    Real>::has_signaling_NaN) { // simple sample points for n=0..127 should not produce NaNs.
     for (Real x : sample_points<Real>())
-      for (unsigned n = 0; n < g_max_n; ++n)
+      for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
         assert(!std::isnan(std::hermite(n, x)));
   }
-#endif
 
   { // checks std::hermite(n, x) for n=0..5 against analytic polynoms
     const auto h0 = [](Real) -> Real { return 1; };
@@ -244,21 +248,21 @@ void test() {
 
   { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float)
     if constexpr (std::is_same_v<Real, float>)
-      for (unsigned n = 0; n < g_max_n; ++n)
+      for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
         for (float x : sample_points<float>())
           assert(std::hermite(n, x) == std::hermitef(n, x));
   }
 
   { // checks std::hermitel for bitwise equality with std::hermite(unsigned, long double)
     if constexpr (std::is_same_v<Real, long double>)
-      for (unsigned n = 0; n < g_max_n; ++n)
+      for (unsigned n = 0; n < get_maximal_order<Real>(); ++n)
         for (long double x : sample_points<long double>())
           assert(std::hermite(n, x) == std::hermitel(n, x));
   }
 
   { // Checks if the characteristic recurrence relation holds:    H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}(x)
     for (Real x : sample_points<Real>()) {
-      for (unsigned n = 1; n < g_max_n - 1; ++n) {
+      for (unsigned n = 1; n < get_maximal_order<Real>() - 1; ++n) {
         Real H_next            = std::hermite(n + 1, x);
         Real H_next_recurrence = 2 * (x * std::hermite(n, x) - n * std::hermite(n - 1, x));
 
@@ -296,23 +300,23 @@ void test() {
     }
   }
 
-#if !(defined(__MVS__) && !defined(__BFP__))
-  { // check input infinity is handled correctly
+  if constexpr (std::numeric_limits<Real>::has_infinity) { // check input infinity is handled correctly
     Real inf = std::numeric_limits<Real>::infinity();
-    for (unsigned n = 1; n < g_max_n; ++n) {
+    for (unsigned n = 1; n < get_maximal_order<Real>(); ++n) {
       assert(std::hermite(n, +inf) == inf);
       assert(std::hermite(n, -inf) == ((n & 1) ? -inf : inf));
     }
   }
 
-  { // check: if overflow occurs that it is mapped to the correct infinity
+  if constexpr (std::numeric_limits<
+                    Real>::has_infinity) { // check: if overflow occurs that it is mapped to the correct infinity
     if constexpr (std::is_same_v<Real, double>) {
       // Q: Why only double?
       // A: The numeric values (e.g. overflow threshold `n`) below are different for other types.
       static_assert(sizeof(double) == 8);
-      for (unsigned n = 0; n < g_max_n; ++n) {
+      for (unsigned n = 0; n < get_maximal_order<Real>(); ++n) {
         // Q: Why n=111 and x=300?
-        // A: Both are chosen s.t. the first overlow occurs for some `n<g_max_n`.
+        // A: Both are chosen s.t. the first overlow occurs for some `n<get_maximal_order<Real>()`.
         if (n < 111) {
           assert(std::isfinite(std::hermite(n, +300.0)));
           assert(std::isfinite(std::hermite(n, -300.0)));
@@ -324,7 +328,6 @@ void test() {
       }
     }
   }
-#endif
 }
 
 struct TestFloat {
@@ -338,7 +341,7 @@ struct TestInt {
   template <class Integer>
   void operator()() {
     // checks that std::hermite(unsigned, Integer) actually wraps std::hermite(unsigned, double)
-    for (unsigned n = 0; n < g_max_n; ++n)
+    for (unsigned n = 0; n < get_maximal_order<double>(); ++n)
       for (Integer x : {-42, -7, -5, -1, 0, 1, 5, 7, 42})
         assert(std::hermite(n, x) == std::hermite(n, static_cast<double>(x)));
   }

>From 112f3d98a0caa308cc5ad5551a33fae74cbca368 Mon Sep 17 00:00:00 2001
From: Zbigniew Sarbinowski <zibi at ca.ibm.com>
Date: Thu, 1 Aug 2024 18:36:45 +0000
Subject: [PATCH 4/5] Addressing comments ...

---
 libcxx/test/std/numerics/c.math/hermite.pass.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
index 28bf27cafc3dd..4b58d9170bdd8 100644
--- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
@@ -28,10 +28,12 @@
 
 template <class Real>
 constexpr unsigned get_maximal_order() {
-  if constexpr (std::numeric_limits<Real>::max_exponent10 < std::numeric_limits<Real>::max_exponent)
+  if constexpr (std::numeric_limits<Real>::max_exponent < 64)
+    return 39;
+  else if constexpr (std::numeric_limits<Real>::max_exponent < 129)
     return 128;
   else
-    return 39;
+    return 1024;
 }
 
 template <class T>

>From 8dfb341ca0cbc684a54e6f34b29f9ac4de772b50 Mon Sep 17 00:00:00 2001
From: Zbigniew Sarbinowski <zibi at ca.ibm.com>
Date: Fri, 2 Aug 2024 20:42:23 +0000
Subject: [PATCH 5/5] more comments...

---
 libcxx/test/std/numerics/c.math/hermite.pass.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
index 4b58d9170bdd8..4283cbfd7bc18 100644
--- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp
@@ -28,12 +28,13 @@
 
 template <class Real>
 constexpr unsigned get_maximal_order() {
-  if constexpr (std::numeric_limits<Real>::max_exponent < 64)
-    return 39;
-  else if constexpr (std::numeric_limits<Real>::max_exponent < 129)
+  if constexpr (std::numeric_limits<Real>::is_iec559)
     return 128;
-  else
-    return 1024;
+  else { // Workaround for z/OS HexFloat.
+    // Note |H_n(x)| < 10^75 for n < 39 and x in sample_points().
+    static_assert(std::numeric_limits<Real>::max_exponent10 == 75);
+    return 39;
+  }
 }
 
 template <class T>



More information about the libcxx-commits mailing list