]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | // Tencent is pleased to support the open source community by making RapidJSON available. |
2 | // | |
1e59de90 | 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. |
31f18b77 FG |
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 | #ifdef __clang__ | |
20 | RAPIDJSON_DIAG_PUSH | |
21 | RAPIDJSON_DIAG_OFF(unreachable-code) | |
22 | #endif | |
23 | ||
24 | #define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1) | |
25 | ||
26 | using namespace rapidjson::internal; | |
27 | ||
28 | TEST(Strtod, CheckApproximationCase) { | |
29 | static const int kSignificandSize = 52; | |
30 | static const int kExponentBias = 0x3FF; | |
31 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); | |
32 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); | |
33 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); | |
34 | ||
35 | // http://www.exploringbinary.com/using-integers-to-check-a-floating-point-approximation/ | |
36 | // Let b = 0x1.465a72e467d88p-149 | |
37 | // = 5741268244528520 x 2^-201 | |
38 | union { | |
39 | double d; | |
40 | uint64_t u; | |
41 | }u; | |
42 | u.u = 0x465a72e467d88 | ((static_cast<uint64_t>(-149 + kExponentBias)) << kSignificandSize); | |
43 | const double b = u.d; | |
44 | const uint64_t bInt = (u.u & kSignificandMask) | kHiddenBit; | |
45 | const int bExp = static_cast<int>(((u.u & kExponentMask) >> kSignificandSize) - kExponentBias - kSignificandSize); | |
46 | EXPECT_DOUBLE_EQ(1.7864e-45, b); | |
47 | EXPECT_EQ(RAPIDJSON_UINT64_C2(0x001465a7, 0x2e467d88), bInt); | |
48 | EXPECT_EQ(-201, bExp); | |
49 | ||
50 | // Let d = 17864 x 10-49 | |
51 | const char dInt[] = "17864"; | |
52 | const int dExp = -49; | |
53 | ||
54 | // Let h = 2^(bExp-1) | |
55 | const int hExp = bExp - 1; | |
56 | EXPECT_EQ(-202, hExp); | |
57 | ||
58 | int dS_Exp2 = 0; | |
59 | int dS_Exp5 = 0; | |
60 | int bS_Exp2 = 0; | |
61 | int bS_Exp5 = 0; | |
62 | int hS_Exp2 = 0; | |
63 | int hS_Exp5 = 0; | |
64 | ||
65 | // Adjust for decimal exponent | |
66 | if (dExp >= 0) { | |
67 | dS_Exp2 += dExp; | |
68 | dS_Exp5 += dExp; | |
69 | } | |
70 | else { | |
71 | bS_Exp2 -= dExp; | |
72 | bS_Exp5 -= dExp; | |
73 | hS_Exp2 -= dExp; | |
74 | hS_Exp5 -= dExp; | |
75 | } | |
76 | ||
77 | // Adjust for binary exponent | |
78 | if (bExp >= 0) | |
79 | bS_Exp2 += bExp; | |
80 | else { | |
81 | dS_Exp2 -= bExp; | |
82 | hS_Exp2 -= bExp; | |
83 | } | |
84 | ||
85 | // Adjust for half ulp exponent | |
86 | if (hExp >= 0) | |
87 | hS_Exp2 += hExp; | |
88 | else { | |
89 | dS_Exp2 -= hExp; | |
90 | bS_Exp2 -= hExp; | |
91 | } | |
92 | ||
93 | // Remove common power of two factor from all three scaled values | |
1e59de90 | 94 | int common_Exp2 = (std::min)(dS_Exp2, (std::min)(bS_Exp2, hS_Exp2)); |
31f18b77 FG |
95 | dS_Exp2 -= common_Exp2; |
96 | bS_Exp2 -= common_Exp2; | |
97 | hS_Exp2 -= common_Exp2; | |
98 | ||
99 | EXPECT_EQ(153, dS_Exp2); | |
100 | EXPECT_EQ(0, dS_Exp5); | |
101 | EXPECT_EQ(1, bS_Exp2); | |
102 | EXPECT_EQ(49, bS_Exp5); | |
103 | EXPECT_EQ(0, hS_Exp2); | |
104 | EXPECT_EQ(49, hS_Exp5); | |
105 | ||
106 | BigInteger dS = BIGINTEGER_LITERAL(dInt); | |
107 | dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<size_t>(dS_Exp2); | |
108 | ||
109 | BigInteger bS(bInt); | |
110 | bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<size_t>(bS_Exp2); | |
111 | ||
112 | BigInteger hS(1); | |
113 | hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<size_t>(hS_Exp2); | |
114 | ||
115 | EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994138521801764465966248930731085529088") == dS); | |
116 | EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS); | |
117 | EXPECT_TRUE(BIGINTEGER_LITERAL("17763568394002504646778106689453125") == hS); | |
118 | ||
119 | EXPECT_EQ(1, dS.Compare(bS)); | |
120 | ||
121 | BigInteger delta(0); | |
122 | EXPECT_FALSE(dS.Difference(bS, &delta)); | |
123 | EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta); | |
124 | EXPECT_TRUE(bS.Difference(dS, &delta)); | |
125 | EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta); | |
126 | ||
127 | EXPECT_EQ(-1, delta.Compare(hS)); | |
128 | } | |
129 | ||
130 | #ifdef __clang__ | |
131 | RAPIDJSON_DIAG_POP | |
132 | #endif |