@@ -126,20 +126,20 @@ inline bool StrtodFast(double d, int p, double* result) {
126
126
}
127
127
128
128
// Compute an approximation and see if it is within 1/2 ULP
129
- inline bool StrtodDiyFp (const char * decimals, size_t length, size_t decimalPosition, int exp , double * result) {
129
+ inline bool StrtodDiyFp (const char * decimals, int dLen, int dExp , double * result) {
130
130
uint64_t significand = 0 ;
131
- size_t i = 0 ; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
132
- for (; i < length ; i++) {
131
+ int i = 0 ; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
132
+ for (; i < dLen ; i++) {
133
133
if (significand > RAPIDJSON_UINT64_C2 (0x19999999 , 0x99999999 ) ||
134
134
(significand == RAPIDJSON_UINT64_C2 (0x19999999 , 0x99999999 ) && decimals[i] > ' 5' ))
135
135
break ;
136
136
significand = significand * 10u + static_cast <unsigned >(decimals[i] - ' 0' );
137
137
}
138
138
139
- if (i < length && decimals[i] >= ' 5' ) // Rounding
139
+ if (i < dLen && decimals[i] >= ' 5' ) // Rounding
140
140
significand++;
141
141
142
- size_t remaining = length - i;
142
+ int remaining = dLen - i;
143
143
const int kUlpShift = 3 ;
144
144
const int kUlp = 1 << kUlpShift ;
145
145
int64_t error = (remaining == 0 ) ? 0 : kUlp / 2 ;
@@ -148,7 +148,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
148
148
v = v.Normalize ();
149
149
error <<= -v.e ;
150
150
151
- const int dExp = static_cast < int >(decimalPosition) - static_cast < int >(i) + exp ;
151
+ dExp += remaining ;
152
152
153
153
int actualExp;
154
154
DiyFp cachedPower = GetCachedPower10 (dExp, &actualExp);
@@ -165,7 +165,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
165
165
int adjustment = dExp - actualExp - 1 ;
166
166
RAPIDJSON_ASSERT (adjustment >= 0 && adjustment < 7 );
167
167
v = v * kPow10 [adjustment];
168
- if (length + static_cast <unsigned >(adjustment)> 19u ) // has more digits than decimal digits in 64-bit
168
+ if (dLen + static_cast <unsigned >(adjustment)> 19u ) // has more digits than decimal digits in 64-bit
169
169
error += kUlp / 2 ;
170
170
}
171
171
@@ -203,9 +203,8 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
203
203
return halfWay - static_cast <unsigned >(error) >= precisionBits || precisionBits >= halfWay + static_cast <unsigned >(error);
204
204
}
205
205
206
- inline double StrtodBigInteger (double approx, const char * decimals, size_t length, size_t decimalPosition, int exp ) {
206
+ inline double StrtodBigInteger (double approx, const char * decimals, int length, int dExp ) {
207
207
const BigInteger dInt (decimals, length);
208
- const int dExp = static_cast <int >(decimalPosition) - static_cast <int >(length) + exp;
209
208
Double a (approx);
210
209
int cmp = CheckWithinHalfULP (a.Value (), dInt, dExp);
211
210
if (cmp < 0 )
@@ -229,41 +228,47 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
229
228
if (StrtodFast (d, p, &result))
230
229
return result;
231
230
231
+ RAPIDJSON_ASSERT (length <= INT_MAX);
232
+ int dLen = static_cast <int >(length);
233
+
234
+ RAPIDJSON_ASSERT (length >= decimalPosition);
235
+ RAPIDJSON_ASSERT (length - decimalPosition <= INT_MAX);
236
+ int dExpAdjust = static_cast <int >(length - decimalPosition);
237
+
238
+ RAPIDJSON_ASSERT (exp >= INT_MIN + dExpAdjust);
239
+ int dExp = exp - dExpAdjust;
240
+
241
+ // Make sure length+dExp does not overflow
242
+ RAPIDJSON_ASSERT (dExp <= INT_MAX - dLen);
243
+
232
244
// Trim leading zeros
233
- while (*decimals == ' 0' && length > 1 ) {
234
- length --;
245
+ while (*decimals == ' 0' && dLen > 1 ) {
246
+ dLen --;
235
247
decimals++;
236
- RAPIDJSON_ASSERT (decimalPosition > 0 );
237
- decimalPosition--;
238
248
}
239
249
240
250
// Trim trailing zeros
241
- while (decimals[length - 1 ] == ' 0' && length > 1 ) {
242
- length--;
243
- RAPIDJSON_ASSERT (decimalPosition > 0 );
244
- decimalPosition--;
245
- exp++;
251
+ while (decimals[dLen - 1 ] == ' 0' && dLen > 1 ) {
252
+ dLen--;
253
+ dExp++;
246
254
}
247
255
248
256
// Trim right-most digits
249
257
const int kMaxDecimalDigit = 780 ;
250
- if (static_cast <int >(length) > kMaxDecimalDigit ) {
251
- int delta = (static_cast <int >(length) - kMaxDecimalDigit );
252
- exp += delta;
253
- RAPIDJSON_ASSERT (decimalPosition > static_cast <unsigned >(delta));
254
- decimalPosition -= static_cast <unsigned >(delta);
255
- length = kMaxDecimalDigit ;
258
+ if (dLen > kMaxDecimalDigit ) {
259
+ dExp += dLen - kMaxDecimalDigit ;
260
+ dLen = kMaxDecimalDigit ;
256
261
}
257
262
258
263
// If too small, underflow to zero
259
- if (int (length) + exp < -324 )
264
+ if (dLen + dExp < -324 )
260
265
return 0.0 ;
261
266
262
- if (StrtodDiyFp (decimals, length, decimalPosition, exp , &result))
267
+ if (StrtodDiyFp (decimals, dLen, dExp , &result))
263
268
return result;
264
269
265
270
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
266
- return StrtodBigInteger (result, decimals, length, decimalPosition, exp );
271
+ return StrtodBigInteger (result, decimals, dLen, dExp );
267
272
}
268
273
269
274
} // namespace internal
0 commit comments