| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
1 |
// Tencent is pleased to support the open source community by making RapidJSON available. |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
2 |
// |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
3 |
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
4 |
// |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
5 |
// Licensed under the MIT License (the "License"); you may not use this file except |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
6 |
// in compliance with the License. You may obtain a copy of the License at |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
7 |
// |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
8 |
// http://opensource.org/licenses/MIT |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
9 |
// |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
10 |
// Unless required by applicable law or agreed to in writing, software distributed |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
11 |
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
12 |
// CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
13 |
// specific language governing permissions and limitations under the License. |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
14 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
15 |
#ifndef CEREAL_RAPIDJSON_STRTOD_ |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
16 |
#define CEREAL_RAPIDJSON_STRTOD_ |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
17 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
18 |
#include "ieee754.h" |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
19 |
#include "biginteger.h" |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
20 |
#include "diyfp.h" |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
21 |
#include "pow10.h" |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
22 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
23 |
CEREAL_RAPIDJSON_NAMESPACE_BEGIN |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
24 |
namespace internal { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
25 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
26 |
inline double FastPath(double significand, int exp) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
27 |
if (exp < -308) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
28 |
return 0.0; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
29 |
else if (exp >= 0) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
30 |
return significand * internal::Pow10(exp); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
31 |
else |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
32 |
return significand / internal::Pow10(-exp); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
33 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
34 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
35 |
inline double StrtodNormalPrecision(double d, int p) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
36 |
if (p < -308) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
37 |
// Prevent expSum < -308, making Pow10(p) = 0 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
38 |
d = FastPath(d, -308); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
39 |
d = FastPath(d, p + 308); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
40 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
41 |
else |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
42 |
d = FastPath(d, p); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
43 |
return d; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
44 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
45 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
46 |
template <typename T> |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
47 |
inline T Min3(T a, T b, T c) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
48 |
T m = a; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
49 |
if (m > b) m = b; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
50 |
if (m > c) m = c; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
51 |
return m; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
52 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
53 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
54 |
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
55 |
const Double db(b); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
56 |
const uint64_t bInt = db.IntegerSignificand(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
57 |
const int bExp = db.IntegerExponent(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
58 |
const int hExp = bExp - 1; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
59 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
60 |
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
61 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
62 |
// Adjust for decimal exponent |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
63 |
if (dExp >= 0) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
64 |
dS_Exp2 += dExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
65 |
dS_Exp5 += dExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
66 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
67 |
else { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
68 |
bS_Exp2 -= dExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
69 |
bS_Exp5 -= dExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
70 |
hS_Exp2 -= dExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
71 |
hS_Exp5 -= dExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
72 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
73 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
74 |
// Adjust for binary exponent |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
75 |
if (bExp >= 0) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
76 |
bS_Exp2 += bExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
77 |
else { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
78 |
dS_Exp2 -= bExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
79 |
hS_Exp2 -= bExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
80 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
81 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
82 |
// Adjust for half ulp exponent |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
83 |
if (hExp >= 0) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
84 |
hS_Exp2 += hExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
85 |
else { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
86 |
dS_Exp2 -= hExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
87 |
bS_Exp2 -= hExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
88 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
89 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
90 |
// Remove common power of two factor from all three scaled values |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
91 |
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
92 |
dS_Exp2 -= common_Exp2; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
93 |
bS_Exp2 -= common_Exp2; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
94 |
hS_Exp2 -= common_Exp2; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
95 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
96 |
BigInteger dS = d; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
97 |
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
98 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
99 |
BigInteger bS(bInt); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
100 |
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
101 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
102 |
BigInteger hS(1); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
103 |
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
104 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
105 |
BigInteger delta(0); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
106 |
dS.Difference(bS, &delta); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
107 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
108 |
return delta.Compare(hS); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
109 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
110 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
111 |
inline bool StrtodFast(double d, int p, double* result) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
112 |
// Use fast path for string-to-double conversion if possible |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
113 |
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
114 |
if (p > 22 && p < 22 + 16) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
115 |
// Fast Path Cases In Disguise |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
116 |
d *= internal::Pow10(p - 22); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
117 |
p = 22; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
118 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
119 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
120 |
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
121 |
*result = FastPath(d, p); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
122 |
return true; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
123 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
124 |
else |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
125 |
return false; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
126 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
127 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
128 |
// Compute an approximation and see if it is within 1/2 ULP |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
129 |
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
130 |
uint64_t significand = 0; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
131 |
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
132 |
for (; i < length; i++) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
133 |
if (significand > CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
134 |
(significand == CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
135 |
break; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
136 |
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0'); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
137 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
138 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
139 |
if (i < length && decimals[i] >= '5') // Rounding |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
140 |
significand++; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
141 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
142 |
size_t remaining = length - i; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
143 |
const unsigned kUlpShift = 3; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
144 |
const unsigned kUlp = 1 << kUlpShift; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
145 |
int64_t error = (remaining == 0) ? 0 : kUlp / 2; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
146 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
147 |
DiyFp v(significand, 0); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
148 |
v = v.Normalize(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
149 |
error <<= -v.e; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
150 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
151 |
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
152 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
153 |
int actualExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
154 |
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
155 |
if (actualExp != dExp) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
156 |
static const DiyFp kPow10[] = { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
157 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
158 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
159 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
160 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
161 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
162 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
163 |
DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
164 |
}; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
165 |
int adjustment = dExp - actualExp - 1; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
166 |
CEREAL_RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
167 |
v = v * kPow10[adjustment]; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
168 |
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
169 |
error += kUlp / 2; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
170 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
171 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
172 |
v = v * cachedPower; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
173 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
174 |
error += kUlp + (error == 0 ? 0 : 1); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
175 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
176 |
const int oldExp = v.e; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
177 |
v = v.Normalize(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
178 |
error <<= oldExp - v.e; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
179 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
180 |
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
181 |
unsigned precisionSize = 64 - effectiveSignificandSize; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
182 |
if (precisionSize + kUlpShift >= 64) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
183 |
unsigned scaleExp = (precisionSize + kUlpShift) - 63; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
184 |
v.f >>= scaleExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
185 |
v.e += scaleExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
186 |
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
187 |
precisionSize -= scaleExp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
188 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
189 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
190 |
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize)); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
191 |
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
192 |
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
193 |
if (precisionBits >= halfWay + static_cast<unsigned>(error)) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
194 |
rounded.f++; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
195 |
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
196 |
rounded.f >>= 1; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
197 |
rounded.e++; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
198 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
199 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
200 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
201 |
*result = rounded.ToDouble(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
202 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
203 |
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
204 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
205 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
206 |
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
207 |
const BigInteger dInt(decimals, length); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
208 |
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
209 |
Double a(approx); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
210 |
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
211 |
if (cmp < 0) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
212 |
return a.Value(); // within half ULP |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
213 |
else if (cmp == 0) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
214 |
// Round towards even |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
215 |
if (a.Significand() & 1) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
216 |
return a.NextPositiveDouble(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
217 |
else |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
218 |
return a.Value(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
219 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
220 |
else // adjustment |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
221 |
return a.NextPositiveDouble(); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
222 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
223 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
224 |
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
225 |
CEREAL_RAPIDJSON_ASSERT(d >= 0.0); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
226 |
CEREAL_RAPIDJSON_ASSERT(length >= 1); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
227 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
228 |
double result; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
229 |
if (StrtodFast(d, p, &result)) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
230 |
return result; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
231 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
232 |
// Trim leading zeros |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
233 |
while (*decimals == '0' && length > 1) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
234 |
length--; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
235 |
decimals++; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
236 |
decimalPosition--; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
237 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
238 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
239 |
// Trim trailing zeros |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
240 |
while (decimals[length - 1] == '0' && length > 1) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
241 |
length--; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
242 |
decimalPosition--; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
243 |
exp++; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
244 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
245 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
246 |
// Trim right-most digits |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
247 |
const int kMaxDecimalDigit = 780; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
248 |
if (static_cast<int>(length) > kMaxDecimalDigit) { |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
249 |
int delta = (static_cast<int>(length) - kMaxDecimalDigit); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
250 |
exp += delta; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
251 |
decimalPosition -= static_cast<unsigned>(delta); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
252 |
length = kMaxDecimalDigit; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
253 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
254 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
255 |
// If too small, underflow to zero |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
256 |
if (int(length) + exp < -324) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
257 |
return 0.0; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
258 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
259 |
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
260 |
return result; |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
261 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
262 |
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
263 |
return StrtodBigInteger(result, decimals, length, decimalPosition, exp); |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
264 |
} |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
265 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
266 |
} // namespace internal |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
267 |
CEREAL_RAPIDJSON_NAMESPACE_END |
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
268 |
|
| 6c5f2c01 |
sago007 |
2017-03-15 17:56 |
269 |
#endif // CEREAL_RAPIDJSON_STRTOD_ |
|
|
1970-01-01 00:00 |
270 |
|