From b29acfb90d1f8714d721e2e322eb349cfca04ccc Mon Sep 17 00:00:00 2001 From: miloyip Date: Mon, 15 Sep 2014 15:54:15 +0800 Subject: [PATCH] Limit significand to 17 digits for fast path Should fix gcc debug error in tranvis. May need further refactoring. --- include/rapidjson/internal/strtod.h | 4 ++-- include/rapidjson/reader.h | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h index 46248bc..939cadb 100644 --- a/include/rapidjson/internal/strtod.h +++ b/include/rapidjson/internal/strtod.h @@ -447,12 +447,11 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adj return cmp; } -inline double FullPrecision(double d, int dExp, const char* decimals, size_t length) { +inline double FullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { RAPIDJSON_ASSERT(d >= 0.0); // Use fast path for string-to-double conversion if possible // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - int p = dExp; if (p > 22) { if (p < 22 + 16) { // Fast Path Cases In Disguise @@ -468,6 +467,7 @@ inline double FullPrecision(double d, int dExp, const char* decimals, size_t len return 0.0; const BigInteger dInt(decimals, length); + const int dExp = (int)decimalPosition - (int)length + exp; Double approx = NormalPrecision(d, p); for (int i = 0; i < 10; i++) { bool adjustToNegative; diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 17faff8..c03a4ce 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -779,6 +779,7 @@ private: unsigned i = 0; uint64_t i64 = 0; bool use64bit = false; + int significandDigit = 0; if (s.Peek() == '0') { i = 0; s.TakePush(); @@ -796,6 +797,7 @@ private: } } i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; } else while (s.Peek() >= '0' && s.Peek() <= '9') { @@ -807,6 +809,7 @@ private: } } i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; } } else @@ -825,6 +828,7 @@ private: break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; } else while (s.Peek() >= '0' && s.Peek() <= '9') { @@ -835,6 +839,7 @@ private: break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; } } @@ -849,8 +854,13 @@ private: // Parse frac = decimal-point 1*DIGIT int expFrac = 0; + size_t decimalPosition; if (s.Peek() == '.') { s.Take(); + decimalPosition = s.Length(); + + if (!(s.Peek() >= '0' && s.Peek() <= '9')) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { #if RAPIDJSON_64BIT @@ -864,6 +874,8 @@ private: else { i64 = i64 * 10 + static_cast(s.TakePush() - '0'); --expFrac; + if (i64 != 0) + significandDigit++; } } @@ -876,13 +888,18 @@ private: } while (s.Peek() >= '0' && s.Peek() <= '9') { - d = d * 10.0 + (s.TakePush() - '0'); - --expFrac; + if (significandDigit < 17) { + d = d * 10.0 + (s.TakePush() - '0'); + --expFrac; + if (d != 0.0) + significandDigit++; + } + else + s.TakePush(); } - - if (expFrac == 0) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); } + else + decimalPosition = s.Length(); // decimal position at the end of integer. // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; @@ -924,7 +941,7 @@ private: if (useDouble) { int p = exp + expFrac; if (parseFlags & kParseFullPrecisionFlag) - d = internal::FullPrecision(d, p, decimal, length); + d = internal::FullPrecision(d, p, decimal, length, decimalPosition, exp); else d = internal::NormalPrecision(d, p);