Commit 359ebc78 authored by Milo Yip's avatar Milo Yip

Extract conversion code to strtod.h [ci skip]

parent 30ea2a32
// 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_
...@@ -26,11 +26,8 @@ ...@@ -26,11 +26,8 @@
#include "rapidjson.h" #include "rapidjson.h"
#include "encodings.h" #include "encodings.h"
#include "internal/meta.h" #include "internal/meta.h"
#include "internal/pow10.h"
#include "internal/stack.h" #include "internal/stack.h"
#include "internal/strtod.h"
#include <cstdlib> // strtod()
#include <cmath> // HUGE_VAL
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
...@@ -763,26 +760,6 @@ private: ...@@ -763,26 +760,6 @@ private:
StackStream<char> stackStream; StackStream<char> 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<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) { void ParseNumber(InputStream& is, Handler& handler) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
...@@ -886,7 +863,7 @@ private: ...@@ -886,7 +863,7 @@ private:
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) { // 2^53 - 1 for fast path if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) { // 2^53 - 1 for fast path
if (parseFlags & kParseFullPrecisionFlag) { if (parseFlags & kParseFullPrecisionFlag) {
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
s.TakeAndPush(); s.TakePush();
--expFrac; --expFrac;
} }
useStrtod = true; useStrtod = true;
...@@ -894,7 +871,7 @@ private: ...@@ -894,7 +871,7 @@ private:
break; break;
} }
else { else {
i64 = i64 * 10 + static_cast<unsigned>(s.TakeAndPush() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
--expFrac; --expFrac;
} }
} }
...@@ -963,30 +940,11 @@ private: ...@@ -963,30 +940,11 @@ private:
if (useDouble) { if (useDouble) {
int p = exp + expFrac; int p = exp + expFrac;
if (parseFlags & kParseFullPrecisionFlag) { if (parseFlags & kParseFullPrecisionFlag)
// Use fast path for string-to-double conversion if possible d = internal::FullPrecision(useStrtod, d, p, str);
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ else
if (!useStrtod && p > 22) { d = internal::NormalPrecision(d, p);
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, exp, expFrac);
d = guess;
}
}
else {
d = NormalPrecision(d, p, exp, expFrac);
}
cont = handler.Double(minus ? -d : d); cont = handler.Double(minus ? -d : d);
} }
else { else {
......
...@@ -262,7 +262,7 @@ static void TestParseDouble() { ...@@ -262,7 +262,7 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, n1e308, 1E308); TEST_DOUBLE(fullPrecision, n1e308, 1E308);
} }
#if 1 #if 0
// Random test for double // Random test for double
{ {
union { union {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment