Fixes StrtodDiyFp bugs
This commit is contained in:
parent
b4e2d58c74
commit
40852f4d6d
@ -179,7 +179,7 @@ struct DiyFp {
|
||||
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||
static const int kDpMinExponent = -kDpExponentBias;
|
||||
static const int kDpDenormalExponent = -kDpExponentBias - 1;
|
||||
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
@ -61,12 +61,12 @@ public:
|
||||
uint64_t ToBias() const { return (u & kSignMask) ? ~u + 1 : u | kSignMask; }
|
||||
|
||||
static unsigned EffectiveSignificandSize(int order) {
|
||||
if (order >= kDenormalExponent + kSignificandSize)
|
||||
return kSignificandSize;
|
||||
else if (order <= kDenormalExponent)
|
||||
if (order >= -1021)
|
||||
return 53;
|
||||
else if (order <= -1074)
|
||||
return 0;
|
||||
else
|
||||
return order - kDenormalExponent;
|
||||
return order + 1074;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -146,27 +146,29 @@ inline bool StrtodFast(double d, int p, double* result) {
|
||||
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
||||
uint64_t significand = 0;
|
||||
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||
for (; i < length && (significand < RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || decimals[i] <= '4'); i++)
|
||||
for (; i < length; i++) {
|
||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||
significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')
|
||||
break;
|
||||
significand = significand * 10 + (decimals[i] - '0');
|
||||
}
|
||||
|
||||
if (i < length && decimals[i] >= '5') // Rounding
|
||||
significand++;
|
||||
|
||||
DiyFp v(significand, 0);
|
||||
size_t remaining = length - i;
|
||||
const int dExp = (int)decimalPosition - (int)i + exp + (int)remaining;
|
||||
|
||||
const unsigned kUlpShift = 3;
|
||||
const unsigned kUlp = 1 << kUlpShift;
|
||||
int error = (remaining == 0) ? 0 : kUlp / 2;
|
||||
|
||||
DiyFp v(significand, 0);
|
||||
v = v.Normalize();
|
||||
error <<= -v.e;
|
||||
|
||||
const int dExp = (int)decimalPosition - (int)i + exp;
|
||||
|
||||
int actualExp;
|
||||
double temp1 = v.ToDouble();
|
||||
v = v * GetCachedPower10(dExp, &actualExp);
|
||||
double temp2 = v.ToDouble();
|
||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||
if (actualExp != dExp) {
|
||||
static const DiyFp kPow10[] = {
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
|
||||
@ -177,9 +179,13 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
||||
};
|
||||
v = v * kPow10[dExp - actualExp - 1];
|
||||
int adjustment = dExp - actualExp - 1;
|
||||
v = v * kPow10[adjustment];
|
||||
if (length + adjustment > 19) // has more digits than decimal digits in 64-bit
|
||||
error += kUlp / 2;
|
||||
}
|
||||
double temp3 = v.ToDouble();
|
||||
|
||||
v = v * cachedPower;
|
||||
|
||||
error += kUlp + (error == 0 ? 0 : 1);
|
||||
|
||||
@ -197,9 +203,9 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||
precisionSize -= scaleExp;
|
||||
}
|
||||
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
|
||||
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
|
||||
if (precisionBits >= halfWay + error)
|
||||
rounded.f++;
|
||||
|
||||
|
@ -195,7 +195,6 @@ static void TestParseDouble() {
|
||||
EXPECT_DOUBLE_EQ(x, h.actual_); \
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST_DOUBLE(fullPrecision, "0.0", 0.0);
|
||||
TEST_DOUBLE(fullPrecision, "1.0", 1.0);
|
||||
TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
|
||||
@ -216,7 +215,6 @@ static void TestParseDouble() {
|
||||
TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
|
||||
TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
|
||||
TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
|
||||
#endif
|
||||
TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
|
||||
TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double
|
||||
TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double
|
||||
@ -259,7 +257,7 @@ static void TestParseDouble() {
|
||||
TEST_DOUBLE(fullPrecision, n1e308, 1E308);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
static const unsigned count = 10000000;
|
||||
// Random test for double
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user