From 359ebc78c0e1939e952fe2e6d1001286c5cf3dbb Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 10 Sep 2014 23:36:09 +0800 Subject: [PATCH] Extract conversion code to strtod.h [ci skip] --- include/rapidjson/internal/strtod.h | 75 +++++++++++++++++++++++++++++ include/rapidjson/reader.h | 56 +++------------------ test/unittest/readertest.cpp | 2 +- 3 files changed, 83 insertions(+), 50 deletions(-) create mode 100644 include/rapidjson/internal/strtod.h diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h new file mode 100644 index 0000000..d65d3fe --- /dev/null +++ b/include/rapidjson/internal/strtod.h @@ -0,0 +1,75 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "pow10.h" + +namespace rapidjson { +namespace internal { + +inline double StrtodFastPath(double significand, int exp) { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); +} + +inline double NormalPrecision(double d, int p) { + if (p < -308) { + // Prevent expSum < -308, making Pow10(p) = 0 + d = StrtodFastPath(d, -308); + d = StrtodFastPath(d, p + 308); + } + else + d = StrtodFastPath(d, p); + return d; +} + +inline double FullPrecision(bool useStrtod, double d, int p, const char* str) { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (!useStrtod && p > 22) { + if (p < 22 + 16) { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + else + useStrtod = true; + } + + if (!useStrtod && p >= -22 && d <= 9007199254740991.0) // 2^53 - 1 + d = StrtodFastPath(d, p); + else { + printf("s=%s p=%d\n", str, p); + double guess = NormalPrecision(d, p); + d = guess; + } + return d; +} + +} // namespace internal +} // namespace rapidjson + +#endif // RAPIDJSON_STRTOD_ diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index c1dd4ca..b429977 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -26,11 +26,8 @@ #include "rapidjson.h" #include "encodings.h" #include "internal/meta.h" -#include "internal/pow10.h" #include "internal/stack.h" - -#include // strtod() -#include // HUGE_VAL +#include "internal/strtod.h" #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include @@ -763,26 +760,6 @@ private: StackStream stackStream; }; - static double StrtodFastPath(double significand, int exp) { - if (exp < -308) - return 0.0; - else if (exp >= 0) - return significand * internal::Pow10(exp); - else - return significand / internal::Pow10(-exp); - } - - static double NormalPrecision(double d, int p, int exp, int expFrac) { - if (p < -308) { - // Prevent expSum < -308, making Pow10(p) = 0 - d = StrtodFastPath(d, exp); - d = StrtodFastPath(d, expFrac); - } - else - d = StrtodFastPath(d, p); - return d; - } - template void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); @@ -886,7 +863,7 @@ private: if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) { // 2^53 - 1 for fast path if (parseFlags & kParseFullPrecisionFlag) { while (s.Peek() >= '0' && s.Peek() <= '9') { - s.TakeAndPush(); + s.TakePush(); --expFrac; } useStrtod = true; @@ -894,7 +871,7 @@ private: break; } else { - i64 = i64 * 10 + static_cast(s.TakeAndPush() - '0'); + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); --expFrac; } } @@ -963,30 +940,11 @@ private: if (useDouble) { int p = exp + expFrac; - if (parseFlags & kParseFullPrecisionFlag) { - // Use fast path for string-to-double conversion if possible - // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - if (!useStrtod && p > 22) { - if (p < 22 + 16) { - // Fast Path Cases In Disguise - d *= internal::Pow10(p - 22); - p = 22; - } - else - useStrtod = true; - } + if (parseFlags & kParseFullPrecisionFlag) + d = internal::FullPrecision(useStrtod, d, p, str); + else + d = internal::NormalPrecision(d, p); - if (!useStrtod && p >= -22 && d <= 9007199254740991.0) // 2^53 - 1 - d = StrtodFastPath(d, p); - else { - printf("s=%s p=%d\n", str, p); - double guess = NormalPrecision(d, p, exp, expFrac); - d = guess; - } - } - else { - d = NormalPrecision(d, p, exp, expFrac); - } cont = handler.Double(minus ? -d : d); } else { diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index c59f5a6..af12717 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -262,7 +262,7 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, n1e308, 1E308); } -#if 1 +#if 0 // Random test for double { union {