From add5a5058178a8c70c205ba89f385e39285ce429 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 14 May 2015 12:03:21 +0800 Subject: [PATCH] Fix some numbers parsed incorrectly Fix #340 --- include/rapidjson/internal/strtod.h | 7 +++++- test/unittest/readertest.cpp | 35 ++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h index fa85286d..ace65f67 100644 --- a/include/rapidjson/internal/strtod.h +++ b/include/rapidjson/internal/strtod.h @@ -191,8 +191,13 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + error) + if (precisionBits >= halfWay + error) { rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } *result = rounded.ToDouble(); diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index bee19a8e..91060637 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -193,7 +193,7 @@ static void TestParseDouble() { EXPECT_DOUBLE_EQ(x, h.actual_); \ } \ } - + TEST_DOUBLE(fullPrecision, "0.0", 0.0); TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289 TEST_DOUBLE(fullPrecision, "1.0", 1.0); @@ -327,15 +327,44 @@ static void TestParseDouble() { if (fullPrecision) { EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); if (d.Uint64Value() != a.Uint64Value()) - printf(" String: %sn Actual: %.17gnExpected: %.17gn", buffer, h.actual_, d.Value()); + printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value()); } else { - EXPECT_EQ(d.Sign(), a.Sign()); /* for 0.0 != -0.0 */ + EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0 EXPECT_DOUBLE_EQ(d.Value(), h.actual_); } } } } + + // Issue #340 + TEST_DOUBLE(fullPrecision, "7.450580596923828e-9", 7.450580596923828e-9); + { + internal::Double d(1.0); + for (int i = 0; i < 324; i++) { + char buffer[32]; + *internal::dtoa(d.Value(), buffer) = '\0'; + + StringStream s(buffer); + ParseDoubleHandler h; + Reader reader; + ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code()); + EXPECT_EQ(1u, h.step_); + internal::Double a(h.actual_); + if (fullPrecision) { + EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); + if (d.Uint64Value() != a.Uint64Value()) + printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value()); + } + else { + EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0 + EXPECT_DOUBLE_EQ(d.Value(), h.actual_); + } + + + d = d.Value() * 0.5; + } + } #undef TEST_DOUBLE }