From 360977f968af5998d3c6300dda5d5a5d387c1057 Mon Sep 17 00:00:00 2001 From: Lenard Szolnoki Date: Sat, 25 Mar 2023 19:26:31 +0000 Subject: [PATCH 1/2] Add negative zero parsing test for all rounding modes. This fails on clang. --- tests/basictest.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 433a9b5..0ea0a00 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -184,6 +184,53 @@ TEST_CASE("parse_zero") { CHECK(float64_parsed == 0); } +TEST_CASE("parse_negative_zero") { + // + // If this function fails, we may be left in a non-standard rounding state. + // + const char * negative_zero = "-0"; + uint64_t float64_parsed; + double f = -0.; + ::memcpy(&float64_parsed, &f, sizeof(f)); + CHECK(float64_parsed == 0x8000'0000'0000'0000); + + fesetround(FE_UPWARD); + auto r1 = fast_float::from_chars(negative_zero, negative_zero + 2, f); + CHECK(r1.ec == std::errc()); + std::cout << "FE_UPWARD parsed negative zero as " << iHexAndDec(f) << std::endl; + CHECK(f == 0); + ::memcpy(&float64_parsed, &f, sizeof(f)); + std::cout << "double as uint64_t is " << float64_parsed << std::endl; + CHECK(float64_parsed == 0x8000'0000'0000'0000); + + fesetround(FE_TOWARDZERO); + auto r2 = fast_float::from_chars(negative_zero, negative_zero + 2, f); + CHECK(r2.ec == std::errc()); + std::cout << "FE_TOWARDZERO parsed negative zero as " << iHexAndDec(f) << std::endl; + CHECK(f == 0); + ::memcpy(&float64_parsed, &f, sizeof(f)); + std::cout << "double as uint64_t is " << float64_parsed << std::endl; + CHECK(float64_parsed == 0x8000'0000'0000'0000); + + fesetround(FE_DOWNWARD); + auto r3 = fast_float::from_chars(negative_zero, negative_zero + 2, f); + CHECK(r3.ec == std::errc()); + std::cout << "FE_DOWNWARD parsed negative zero as " << iHexAndDec(f) << std::endl; + CHECK(f == 0); + ::memcpy(&float64_parsed, &f, sizeof(f)); + std::cout << "double as uint64_t is " << float64_parsed << std::endl; + CHECK(float64_parsed == 0x8000'0000'0000'0000); + + fesetround(FE_TONEAREST); + auto r4 = fast_float::from_chars(negative_zero, negative_zero + 2, f); + CHECK(r4.ec == std::errc()); + std::cout << "FE_TONEAREST parsed negative zero as " << iHexAndDec(f) << std::endl; + CHECK(f == 0); + ::memcpy(&float64_parsed, &f, sizeof(f)); + std::cout << "double as uint64_t is " << float64_parsed << std::endl; + CHECK(float64_parsed == 0x8000'0000'0000'0000); +} + // C++ 17 because it is otherwise annoying to browse all files in a directory. // We also only run these tests on little endian systems. #if (FASTFLOAT_CPLUSPLUS >= 201703L) && (FASTFLOAT_IS_BIG_ENDIAN == 0) && !defined(FASTFLOAT_ODDPLATFORM) From 5b8290433c3cb47ec76bc19eea11b91049504c03 Mon Sep 17 00:00:00 2001 From: Lenard Szolnoki Date: Sat, 25 Mar 2023 19:38:44 +0000 Subject: [PATCH 2/2] Fix clang workaround for parsing -0 on non-nearest rounding mode --- include/fast_float/parse_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 5f5c264..7bb1bc9 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -191,7 +191,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last, #if defined(__clang__) // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD if(pns.mantissa == 0) { - value = 0; + value = pns.negative ? -0. : 0.; return answer; } #endif