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
21using namespace rapidjson::internal;
22
23TEST(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