Commit 4e9b4f6d authored by abolz's avatar abolz

Return 0 if binary exponent is too small

parent f5e5d47f
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication: // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
...@@ -56,7 +56,7 @@ struct DiyFp { ...@@ -56,7 +56,7 @@ struct DiyFp {
if (biased_e != 0) { if (biased_e != 0) {
f = significand + kDpHiddenBit; f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias; e = biased_e - kDpExponentBias;
} }
else { else {
f = significand; f = significand;
e = kDpMinExponent + 1; e = kDpMinExponent + 1;
...@@ -142,9 +142,12 @@ struct DiyFp { ...@@ -142,9 +142,12 @@ struct DiyFp {
uint64_t u64; uint64_t u64;
}u; }u;
RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
RAPIDJSON_ASSERT(e >= kDpDenormalExponent); if (e < kDpDenormalExponent) {
// Underflow.
return 0.0;
}
RAPIDJSON_ASSERT(e < kDpMaxExponent); RAPIDJSON_ASSERT(e < kDpMaxExponent);
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias); static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d; return u.d;
...@@ -226,7 +229,7 @@ inline DiyFp GetCachedPowerByIndex(size_t index) { ...@@ -226,7 +229,7 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
RAPIDJSON_ASSERT(index < 87); RAPIDJSON_ASSERT(index < 87);
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
} }
inline DiyFp GetCachedPower(int e, int* K) { inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
......
...@@ -392,6 +392,15 @@ static void TestParseDouble() { ...@@ -392,6 +392,15 @@ static void TestParseDouble() {
"83723677529752585477247372368372368547354737253685475529752", "83723677529752585477247372368372368547354737253685475529752",
6223372036854775808.0); 6223372036854775808.0);
TEST_DOUBLE(fullPrecision, "1e-325", 0.0);
TEST_DOUBLE(fullPrecision, "1e-324", 0.0);
TEST_DOUBLE(fullPrecision, "2e-324", 0.0);
TEST_DOUBLE(fullPrecision, "2.4703282292062327e-324", 0.0);
TEST_DOUBLE(fullPrecision, "2.4703282292062328e-324", 2.4703282292062328e-324);
TEST_DOUBLE(fullPrecision, "2.48e-324", 2.48e-324);
TEST_DOUBLE(fullPrecision, "2.5e-324", 2.5e-324);
#undef TEST_DOUBLE #undef TEST_DOUBLE
} }
...@@ -1346,20 +1355,20 @@ TEST(Reader, IterativePullParsing_General) { ...@@ -1346,20 +1355,20 @@ TEST(Reader, IterativePullParsing_General) {
handler.LOG_DOUBLE, handler.LOG_DOUBLE,
handler.LOG_ENDARRAY | 7 handler.LOG_ENDARRAY | 7
}; };
StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]"); StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]");
Reader reader; Reader reader;
reader.IterativeParseInit(); reader.IterativeParseInit();
while (!reader.IterativeParseComplete()) { while (!reader.IterativeParseComplete()) {
size_t oldLogCount = handler.LogCount; size_t oldLogCount = handler.LogCount;
EXPECT_TRUE(oldLogCount < sizeof(e) / sizeof(int)) << "overrun"; EXPECT_TRUE(oldLogCount < sizeof(e) / sizeof(int)) << "overrun";
EXPECT_TRUE(reader.IterativeParseNext<kParseDefaultFlags>(is, handler)) << "parse fail"; EXPECT_TRUE(reader.IterativeParseNext<kParseDefaultFlags>(is, handler)) << "parse fail";
EXPECT_EQ(handler.LogCount, oldLogCount + 1) << "handler should be invoked exactly once each time"; EXPECT_EQ(handler.LogCount, oldLogCount + 1) << "handler should be invoked exactly once each time";
EXPECT_EQ(e[oldLogCount], handler.Logs[oldLogCount]) << "wrong event returned"; EXPECT_EQ(e[oldLogCount], handler.Logs[oldLogCount]) << "wrong event returned";
} }
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount) << "handler invoked wrong number of times"; EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount) << "handler invoked wrong number of times";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment