[PATCH 1/2] libstdc++: Robustify long double std::to_chars testcase [PR98384]
Patrick Palka
ppalka@redhat.com
Mon Feb 22 21:55:58 GMT 2021
This makes the hexadecimal section of the long double std::to_chars
testcase more robust by avoiding false-negative FAILs due to printf
using a different leading hex digit than us, and by additionally
verifying the correctness of the hexadecimal form via round-tripping
through std::from_chars.
Tested on x86, x86_64, powerpc64be, powerpc64le and aarch64. Does this
look OK for trunk?
libstdc++-v3/ChangeLog:
PR libstdc++/98384
* testsuite/20_util/to_chars/long_double.cc: Include <optional>.
(test01): Simplify verifying the nearby values by using a
2-iteration loop and a dedicated output buffer to check that the
nearby values are different. Factor out the printf-based
verification into a local function, and check that the leading
hex digits agree before comparing with the output of printf.
Also verify the output by round-tripping it through from_chars.
---
.../testsuite/20_util/to_chars/long_double.cc | 73 ++++++++++++-------
1 file changed, 47 insertions(+), 26 deletions(-)
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
index 4f72cb65400..34cc03034cc 100644
--- a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
+++ b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
@@ -26,6 +26,7 @@
#include <cmath>
#include <cstring>
#include <iterator>
+#include <optional>
#include <limits>
#include <testsuite_hooks.h>
@@ -50,6 +51,38 @@ namespace detail
void
test01()
{
+ // Verifies correctness of the hexadecimal form [BEGIN,END) for VALUE by
+ // round-tripping it through from_chars (if available).
+ auto verify_via_from_chars = [] (char *begin, char *end, long double value) {
+#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
+ long double roundtrip;
+ auto result = from_chars(begin, end, roundtrip, chars_format::hex);
+ VERIFY( result.ec == errc{} );
+ VERIFY( result.ptr == end );
+ VERIFY( roundtrip == value );
+#endif
+ };
+
+ // Verifies correctness of the null-terminated hexadecimal form at BEGIN
+ // for VALUE and PRECISION by comparing it with the output of printf's %La
+ // conversion specifier.
+ auto verify_via_printf = [] (char *begin, long double value,
+ optional<int> precision = nullopt) {
+ char printf_buffer[1024] = {};
+ if (precision.has_value())
+ sprintf(printf_buffer, "%.*La", precision.value(), value);
+ else
+ sprintf(printf_buffer, "%La", value);
+
+ // Only compare with the output of printf if the leading hex digits agree.
+ // If the leading hex digit of our form doesn't agree with that of printf,
+ // then the two forms may still be equivalent (e.g. 1.1p+0 vs 8.8p-3), so we
+ // don't want a FAIL in this case. But if the leading hex digits do agree,
+ // then we do expect the two forms to be the same.
+ if (printf_buffer[strlen("0x")] == begin[0])
+ VERIFY( !strcmp(begin, printf_buffer+strlen("0x")) );
+ };
+
const long double hex_testcases[]
= { detail::nextdownl(numeric_limits<long double>::max()),
detail::nextupl(numeric_limits<long double>::min()),
@@ -92,38 +125,27 @@ test01()
if (testcase == 0.0L || isinf(testcase))
continue;
- char to_chars_buffer[1024], printf_buffer[1024];
- memset(to_chars_buffer, '\0', sizeof(to_chars_buffer));
- memset(printf_buffer, '\0', sizeof(printf_buffer));
-
+ char to_chars_buffer[1024] = {};
auto result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
testcase, chars_format::hex);
VERIFY( result.ec == errc{} );
*result.ptr = '\0';
- sprintf(printf_buffer, "%La", testcase);
- VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
+ verify_via_from_chars(begin(to_chars_buffer), result.ptr, testcase);
+ verify_via_printf(to_chars_buffer, testcase);
+ // Verify the nearby values, and also check they have a different
+ // shortest form.
+ for (long double nearby
+ : { detail::nextdownl(testcase), detail::nextupl(testcase) })
{
- // Verify that the nearby values have a different shortest form.
- testcase = detail::nextdownl(testcase);
- result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
- testcase, chars_format::hex);
- VERIFY( result.ec == errc{} );
- *result.ptr = '\0';
- VERIFY( strcmp(to_chars_buffer, printf_buffer+strlen("0x")) != 0);
- sprintf(printf_buffer, "%La", testcase);
- VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
-
- testcase = detail::nextupl(detail::nextupl(testcase));
- result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
- testcase, chars_format::hex);
+ char nearby_buffer[1024] = {};
+ result = to_chars(begin(nearby_buffer), end(nearby_buffer),
+ nearby, chars_format::hex);
VERIFY( result.ec == errc{} );
*result.ptr = '\0';
- VERIFY( strcmp(to_chars_buffer, printf_buffer+strlen("0x")) != 0);
- sprintf(printf_buffer, "%La", testcase);
- VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
-
- testcase = detail::nextdownl(testcase);
+ VERIFY( strcmp(nearby_buffer, to_chars_buffer) != 0);
+ verify_via_from_chars(begin(nearby_buffer), result.ptr, nearby);
+ verify_via_printf(nearby_buffer, nearby);
}
for (int precision = -1; precision < 50; precision++)
@@ -132,8 +154,7 @@ test01()
testcase, chars_format::hex, precision);
VERIFY( result.ec == errc{} );
*result.ptr = '\0';
- sprintf(printf_buffer, "%.*La", precision, testcase);
- VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
+ verify_via_printf(to_chars_buffer, testcase, precision);
}
}
}
--
2.30.1.559.g2283e0e9af
More information about the Libstdc++
mailing list