#include <cmath>
#include <cstring>
#include <iterator>
+#include <optional>
#include <limits>
#include <testsuite_hooks.h>
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). 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()),
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++)
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);
}
}
}