strtod.h Source File

strtod.h Source File#

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