mirror of
https://github.com/Tencent/rapidjson.git
synced 2025-03-06 13:41:35 +01:00
Replace unsigned with signed integer arithmetic in strtod
This commit is contained in:
parent
29b6c9b7dc
commit
c59ecc857d
@ -126,20 +126,20 @@ inline bool StrtodFast(double d, int p, double* result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute an approximation and see if it is within 1/2 ULP
|
// Compute an approximation and see if it is within 1/2 ULP
|
||||||
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
|
||||||
uint64_t significand = 0;
|
uint64_t significand = 0;
|
||||||
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||||
for (; i < length; i++) {
|
for (; i < dLen; i++) {
|
||||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||||
break;
|
break;
|
||||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < length && decimals[i] >= '5') // Rounding
|
if (i < dLen && decimals[i] >= '5') // Rounding
|
||||||
significand++;
|
significand++;
|
||||||
|
|
||||||
size_t remaining = length - i;
|
int remaining = dLen - i;
|
||||||
const int kUlpShift = 3;
|
const int kUlpShift = 3;
|
||||||
const int kUlp = 1 << kUlpShift;
|
const int kUlp = 1 << kUlpShift;
|
||||||
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||||
@ -148,7 +148,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
|||||||
v = v.Normalize();
|
v = v.Normalize();
|
||||||
error <<= -v.e;
|
error <<= -v.e;
|
||||||
|
|
||||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
|
dExp += remaining;
|
||||||
|
|
||||||
int actualExp;
|
int actualExp;
|
||||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||||
@ -165,7 +165,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
|||||||
int adjustment = dExp - actualExp - 1;
|
int adjustment = dExp - actualExp - 1;
|
||||||
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
||||||
v = v * kPow10[adjustment];
|
v = v * kPow10[adjustment];
|
||||||
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
if (dLen + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
||||||
error += kUlp / 2;
|
error += kUlp / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,9 +203,8 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
|||||||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
inline double StrtodBigInteger(double approx, const char* decimals, int length, int dExp) {
|
||||||
const BigInteger dInt(decimals, length);
|
const BigInteger dInt(decimals, length);
|
||||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
|
|
||||||
Double a(approx);
|
Double a(approx);
|
||||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||||
if (cmp < 0)
|
if (cmp < 0)
|
||||||
@ -229,41 +228,47 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
|
|||||||
if (StrtodFast(d, p, &result))
|
if (StrtodFast(d, p, &result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(length <= INT_MAX);
|
||||||
|
int dLen = static_cast<int>(length);
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(length >= decimalPosition);
|
||||||
|
RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
|
||||||
|
int dExpAdjust = static_cast<int>(length - decimalPosition);
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
|
||||||
|
int dExp = exp - dExpAdjust;
|
||||||
|
|
||||||
|
// Make sure length+dExp does not overflow
|
||||||
|
RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
|
||||||
|
|
||||||
// Trim leading zeros
|
// Trim leading zeros
|
||||||
while (*decimals == '0' && length > 1) {
|
while (*decimals == '0' && dLen > 1) {
|
||||||
length--;
|
dLen--;
|
||||||
decimals++;
|
decimals++;
|
||||||
RAPIDJSON_ASSERT(decimalPosition > 0);
|
|
||||||
decimalPosition--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim trailing zeros
|
// Trim trailing zeros
|
||||||
while (decimals[length - 1] == '0' && length > 1) {
|
while (decimals[dLen - 1] == '0' && dLen > 1) {
|
||||||
length--;
|
dLen--;
|
||||||
RAPIDJSON_ASSERT(decimalPosition > 0);
|
dExp++;
|
||||||
decimalPosition--;
|
|
||||||
exp++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim right-most digits
|
// Trim right-most digits
|
||||||
const int kMaxDecimalDigit = 780;
|
const int kMaxDecimalDigit = 780;
|
||||||
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
if (dLen > kMaxDecimalDigit) {
|
||||||
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
dExp += dLen - kMaxDecimalDigit;
|
||||||
exp += delta;
|
dLen = kMaxDecimalDigit;
|
||||||
RAPIDJSON_ASSERT(decimalPosition > static_cast<unsigned>(delta));
|
|
||||||
decimalPosition -= static_cast<unsigned>(delta);
|
|
||||||
length = kMaxDecimalDigit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If too small, underflow to zero
|
// If too small, underflow to zero
|
||||||
if (int(length) + exp < -324)
|
if (dLen + dExp < -324)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
|
if (StrtodDiyFp(decimals, dLen, dExp, &result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||||
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
|
return StrtodBigInteger(result, decimals, dLen, dExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
Loading…
x
Reference in New Issue
Block a user