Skip to content

Commit c59ecc8

Browse files
committed
Replace unsigned with signed integer arithmetic in strtod
1 parent 29b6c9b commit c59ecc8

File tree

1 file changed

+32
-27
lines changed

1 file changed

+32
-27
lines changed

include/rapidjson/internal/strtod.h

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,20 @@ inline bool StrtodFast(double d, int p, double* result) {
126126
}
127127

128128
// 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) {
130130
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++) {
133133
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
134134
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
135135
break;
136136
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
137137
}
138138

139-
if (i < length && decimals[i] >= '5') // Rounding
139+
if (i < dLen && decimals[i] >= '5') // Rounding
140140
significand++;
141141

142-
size_t remaining = length - i;
142+
int remaining = dLen - i;
143143
const int kUlpShift = 3;
144144
const int kUlp = 1 << kUlpShift;
145145
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
@@ -148,7 +148,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
148148
v = v.Normalize();
149149
error <<= -v.e;
150150

151-
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
151+
dExp += remaining;
152152

153153
int actualExp;
154154
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
@@ -165,7 +165,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
165165
int adjustment = dExp - actualExp - 1;
166166
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
167167
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
169169
error += kUlp / 2;
170170
}
171171

@@ -203,9 +203,8 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
203203
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
204204
}
205205

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) {
207207
const BigInteger dInt(decimals, length);
208-
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
209208
Double a(approx);
210209
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
211210
if (cmp < 0)
@@ -229,41 +228,47 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
229228
if (StrtodFast(d, p, &result))
230229
return result;
231230

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+
232244
// Trim leading zeros
233-
while (*decimals == '0' && length > 1) {
234-
length--;
245+
while (*decimals == '0' && dLen > 1) {
246+
dLen--;
235247
decimals++;
236-
RAPIDJSON_ASSERT(decimalPosition > 0);
237-
decimalPosition--;
238248
}
239249

240250
// 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++;
246254
}
247255

248256
// Trim right-most digits
249257
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;
256261
}
257262

258263
// If too small, underflow to zero
259-
if (int(length) + exp < -324)
264+
if (dLen + dExp < -324)
260265
return 0.0;
261266

262-
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
267+
if (StrtodDiyFp(decimals, dLen, dExp, &result))
263268
return result;
264269

265270
// 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);
267272
}
268273

269274
} // namespace internal

0 commit comments

Comments
 (0)