1 // Tencent is pleased to support the open source community by making RapidJSON available. 2 // 3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 // 5 // Licensed under the MIT License (the "License"); you may not use this file except 6 // in compliance with the License. You may obtain a copy of the License at 7 // 8 // http://opensource.org/licenses/MIT 9 // 10 // Unless required by applicable law or agreed to in writing, software distributed 11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 // specific language governing permissions and limitations under the License. 14 15 #include "unittest.h" 16 17 #include "rapidjson/internal/strtod.h" 18 19 #define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1) 20 21 using namespace rapidjson::internal; 22 23 TEST(Strtod, CheckApproximationCase) { 24 static const int kSignificandSize = 52; 25 static const int kExponentBias = 0x3FF; 26 static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 27 static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 28 static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 29 30 // http://www.exploringbinary.com/using-integers-to-check-a-floating-point-approximation/ 31 // Let b = 0x1.465a72e467d88p-149 32 // = 5741268244528520 x 2^-201 33 union { 34 double d; 35 uint64_t u; 36 }u; 37 u.u = 0x465a72e467d88 | ((static_cast<uint64_t>(-149 + kExponentBias)) << kSignificandSize); 38 const double b = u.d; 39 const uint64_t bInt = (u.u & kSignificandMask) | kHiddenBit; 40 const int bExp = ((u.u & kExponentMask) >> kSignificandSize) - kExponentBias - kSignificandSize; 41 EXPECT_DOUBLE_EQ(1.7864e-45, b); 42 EXPECT_EQ(RAPIDJSON_UINT64_C2(0x001465a7, 0x2e467d88), bInt); 43 EXPECT_EQ(-201, bExp); 44 45 // Let d = 17864 x 10-49 46 const char dInt[] = "17864"; 47 const int dExp = -49; 48 49 // Let h = 2^(bExp-1) 50 const int hExp = bExp - 1; 51 EXPECT_EQ(-202, hExp); 52 53 int dS_Exp2 = 0; 54 int dS_Exp5 = 0; 55 int bS_Exp2 = 0; 56 int bS_Exp5 = 0; 57 int hS_Exp2 = 0; 58 int hS_Exp5 = 0; 59 60 // Adjust for decimal exponent 61 if (dExp >= 0) { 62 dS_Exp2 += dExp; 63 dS_Exp5 += dExp; 64 } 65 else { 66 bS_Exp2 -= dExp; 67 bS_Exp5 -= dExp; 68 hS_Exp2 -= dExp; 69 hS_Exp5 -= dExp; 70 } 71 72 // Adjust for binary exponent 73 if (bExp >= 0) 74 bS_Exp2 += bExp; 75 else { 76 dS_Exp2 -= bExp; 77 hS_Exp2 -= bExp; 78 } 79 80 // Adjust for half ulp exponent 81 if (hExp >= 0) 82 hS_Exp2 += hExp; 83 else { 84 dS_Exp2 -= hExp; 85 bS_Exp2 -= hExp; 86 } 87 88 // Remove common power of two factor from all three scaled values 89 int common_Exp2 = std::min(dS_Exp2, std::min(bS_Exp2, hS_Exp2)); 90 dS_Exp2 -= common_Exp2; 91 bS_Exp2 -= common_Exp2; 92 hS_Exp2 -= common_Exp2; 93 94 EXPECT_EQ(153, dS_Exp2); 95 EXPECT_EQ(0, dS_Exp5); 96 EXPECT_EQ(1, bS_Exp2); 97 EXPECT_EQ(49, bS_Exp5); 98 EXPECT_EQ(0, hS_Exp2); 99 EXPECT_EQ(49, hS_Exp5); 100 101 BigInteger dS = BIGINTEGER_LITERAL(dInt); 102 dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2; 103 104 BigInteger bS(bInt); 105 bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2; 106 107 BigInteger hS(1); 108 hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; 109 110 EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994138521801764465966248930731085529088") == dS); 111 EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS); 112 EXPECT_TRUE(BIGINTEGER_LITERAL("17763568394002504646778106689453125") == hS); 113 114 EXPECT_EQ(1, dS.Compare(bS)); 115 116 BigInteger delta(0); 117 EXPECT_FALSE(dS.Difference(bS, &delta)); 118 EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta); 119 EXPECT_TRUE(bS.Difference(dS, &delta)); 120 EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta); 121 122 EXPECT_EQ(-1, delta.Compare(hS)); 123 } 124