Extract conversion code to strtod.h [ci skip]
This commit is contained in:
parent
30ea2a32d1
commit
359ebc78c0
75
include/rapidjson/internal/strtod.h
Normal file
75
include/rapidjson/internal/strtod.h
Normal file
@ -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_
|
@ -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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
|
|
||||||
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() {
|
|||||||
TEST_DOUBLE(fullPrecision, n1e308, 1E308);
|
TEST_DOUBLE(fullPrecision, n1e308, 1E308);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
// Random test for double
|
// Random test for double
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user