From f343fee8c5c9526b3cf62ee6d450c44b69a47e87 Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski Date: Wed, 7 Aug 2024 09:09:06 -0400 Subject: [PATCH] [libcxx][test][z/OS] Fix hermite.pass.cpp for HEX float (#101019) The HEX float on z/OS does not have infinity nor NaN. In addition, the limits are smaller before the overflow occurs in mathematical calculations. This PR accounts for this. FYI, this LIT test was recently added in PR [89982](https://github.com/llvm/llvm-project/pull/89982) --- .../test/std/numerics/c.math/hermite.pass.cpp | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/libcxx/test/std/numerics/c.math/hermite.pass.cpp b/libcxx/test/std/numerics/c.math/hermite.pass.cpp index 08fbd5c3283c17..4283cbfd7bc18d 100644 --- a/libcxx/test/std/numerics/c.math/hermite.pass.cpp +++ b/libcxx/test/std/numerics/c.math/hermite.pass.cpp @@ -26,7 +26,16 @@ #include "type_algorithms.h" -inline constexpr unsigned g_max_n = 128; +template +constexpr unsigned get_maximal_order() { + if constexpr (std::numeric_limits::is_iec559) + return 128; + 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::max_exponent10 == 75); + return 39; + } +} template std::array sample_points() { @@ -203,16 +212,21 @@ std::vector get_roots(unsigned n) { template void test() { - { // checks if NaNs are reported correctly (i.e. output == input for input == NaN) + if constexpr ( + std::numeric_limits::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; 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(); ++n) assert(std::isnan(std::hermite(n, NaN))); } - { // simple sample points for n=0..127 should not produce NaNs. + if constexpr (std::numeric_limits::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()) - for (unsigned n = 0; n < g_max_n; ++n) + for (unsigned n = 0; n < get_maximal_order(); ++n) assert(!std::isnan(std::hermite(n, x))); } @@ -237,21 +251,21 @@ void test() { { // checks std::hermitef for bitwise equality with std::hermite(unsigned, float) if constexpr (std::is_same_v) - for (unsigned n = 0; n < g_max_n; ++n) + for (unsigned n = 0; n < get_maximal_order(); ++n) for (float x : sample_points()) 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) - for (unsigned n = 0; n < g_max_n; ++n) + for (unsigned n = 0; n < get_maximal_order(); ++n) for (long double x : sample_points()) 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()) { - for (unsigned n = 1; n < g_max_n - 1; ++n) { + for (unsigned n = 1; n < get_maximal_order() - 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)); @@ -289,22 +303,23 @@ void test() { } } - { // check input infinity is handled correctly + if constexpr (std::numeric_limits::has_infinity) { // check input infinity is handled correctly Real inf = std::numeric_limits::infinity(); - for (unsigned n = 1; n < g_max_n; ++n) { + for (unsigned n = 1; n < get_maximal_order(); ++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) { // 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(); ++n) { // Q: Why n=111 and x=300? - // A: Both are chosen s.t. the first overlow occurs for some `n()`. if (n < 111) { assert(std::isfinite(std::hermite(n, +300.0))); assert(std::isfinite(std::hermite(n, -300.0))); @@ -329,7 +344,7 @@ struct TestInt { template 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(); ++n) for (Integer x : {-42, -7, -5, -1, 0, 1, 5, 7, 42}) assert(std::hermite(n, x) == std::hermite(n, static_cast(x))); }