]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // Copyright 2018 Ulf Adams |
2 | // | |
3 | // The contents of this file may be used under the terms of the Apache License, | |
4 | // Version 2.0. | |
5 | // | |
6 | // (See accompanying file LICENSE-Apache or copy at | |
7 | // http://www.apache.org/licenses/LICENSE-2.0) | |
8 | // | |
9 | // Alternatively, the contents of this file may be used under the terms of | |
10 | // the Boost Software License, Version 1.0. | |
11 | // (See accompanying file LICENSE-Boost or copy at | |
12 | // https://www.boost.org/LICENSE_1_0.txt) | |
13 | // | |
14 | // Unless required by applicable law or agreed to in writing, this software | |
15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
16 | // KIND, either express or implied. | |
17 | ||
18 | /* | |
19 | This is a derivative work | |
20 | */ | |
21 | ||
22 | #include <boost/json/detail/ryu/ryu.hpp> | |
23 | #include <cmath> | |
24 | #include "gtest.hpp" | |
25 | ||
26 | BOOST_JSON_NS_BEGIN | |
27 | namespace detail { | |
28 | ||
29 | namespace ryu { | |
30 | ||
31 | static double int64Bits2Double(uint64_t bits) { | |
32 | double f; | |
33 | memcpy(&f, &bits, sizeof(double)); | |
34 | return f; | |
35 | } | |
36 | ||
37 | static double ieeeParts2Double(const bool sign, const uint32_t ieeeExponent, const uint64_t ieeeMantissa) { | |
38 | BOOST_ASSERT(ieeeExponent <= 2047); | |
39 | BOOST_ASSERT(ieeeMantissa <= ((std::uint64_t)1 << 53) - 1); | |
40 | return int64Bits2Double(((std::uint64_t)sign << 63) | ((std::uint64_t)ieeeExponent << 52) | ieeeMantissa); | |
41 | } | |
42 | ||
43 | TEST(D2sTest, Basic) { | |
44 | ASSERT_STREQ("0E0", d2s(0.0)); | |
45 | ASSERT_STREQ("-0E0", d2s(-0.0)); | |
46 | ASSERT_STREQ("1E0", d2s(1.0)); | |
47 | ASSERT_STREQ("-1E0", d2s(-1.0)); | |
48 | ASSERT_STREQ("NaN", d2s(NAN)); | |
49 | ASSERT_STREQ("Infinity", d2s(INFINITY)); | |
50 | ASSERT_STREQ("-Infinity", d2s(-INFINITY)); | |
51 | } | |
52 | ||
53 | TEST(D2sTest, SwitchToSubnormal) { | |
54 | ASSERT_STREQ("2.2250738585072014E-308", d2s(2.2250738585072014E-308)); | |
55 | } | |
56 | ||
57 | TEST(D2sTest, MinAndMax) { | |
58 | ASSERT_STREQ("1.7976931348623157E308", d2s(int64Bits2Double(0x7fefffffffffffff))); | |
59 | ASSERT_STREQ("5E-324", d2s(int64Bits2Double(1))); | |
60 | } | |
61 | ||
62 | TEST(D2sTest, LotsOfTrailingZeros) { | |
63 | ASSERT_STREQ("2.9802322387695312E-8", d2s(2.98023223876953125E-8)); | |
64 | } | |
65 | ||
66 | TEST(D2sTest, Regression) { | |
67 | ASSERT_STREQ("-2.109808898695963E16", d2s(-2.109808898695963E16)); | |
68 | ASSERT_STREQ("4.940656E-318", d2s(4.940656E-318)); | |
69 | ASSERT_STREQ("1.18575755E-316", d2s(1.18575755E-316)); | |
70 | ASSERT_STREQ("2.989102097996E-312", d2s(2.989102097996E-312)); | |
71 | ASSERT_STREQ("9.0608011534336E15", d2s(9.0608011534336E15)); | |
72 | ASSERT_STREQ("4.708356024711512E18", d2s(4.708356024711512E18)); | |
73 | ASSERT_STREQ("9.409340012568248E18", d2s(9.409340012568248E18)); | |
74 | ASSERT_STREQ("1.2345678E0", d2s(1.2345678)); | |
75 | } | |
76 | ||
77 | TEST(D2sTest, LooksLikePow5) { | |
78 | // These numbers have a mantissa that is a multiple of the largest power of 5 that fits, | |
79 | // and an exponent that causes the computation for q to result in 22, which is a corner | |
80 | // case for Ryu. | |
81 | ASSERT_STREQ("5.764607523034235E39", d2s(int64Bits2Double(0x4830F0CF064DD592))); | |
82 | ASSERT_STREQ("1.152921504606847E40", d2s(int64Bits2Double(0x4840F0CF064DD592))); | |
83 | ASSERT_STREQ("2.305843009213694E40", d2s(int64Bits2Double(0x4850F0CF064DD592))); | |
84 | } | |
85 | ||
86 | TEST(D2sTest, OutputLength) { | |
87 | ASSERT_STREQ("1E0", d2s(1)); // already tested in Basic | |
88 | ASSERT_STREQ("1.2E0", d2s(1.2)); | |
89 | ASSERT_STREQ("1.23E0", d2s(1.23)); | |
90 | ASSERT_STREQ("1.234E0", d2s(1.234)); | |
91 | ASSERT_STREQ("1.2345E0", d2s(1.2345)); | |
92 | ASSERT_STREQ("1.23456E0", d2s(1.23456)); | |
93 | ASSERT_STREQ("1.234567E0", d2s(1.234567)); | |
94 | ASSERT_STREQ("1.2345678E0", d2s(1.2345678)); // already tested in Regression | |
95 | ASSERT_STREQ("1.23456789E0", d2s(1.23456789)); | |
96 | ASSERT_STREQ("1.234567895E0", d2s(1.234567895)); // 1.234567890 would be trimmed | |
97 | ASSERT_STREQ("1.2345678901E0", d2s(1.2345678901)); | |
98 | ASSERT_STREQ("1.23456789012E0", d2s(1.23456789012)); | |
99 | ASSERT_STREQ("1.234567890123E0", d2s(1.234567890123)); | |
100 | ASSERT_STREQ("1.2345678901234E0", d2s(1.2345678901234)); | |
101 | ASSERT_STREQ("1.23456789012345E0", d2s(1.23456789012345)); | |
102 | ASSERT_STREQ("1.234567890123456E0", d2s(1.234567890123456)); | |
103 | ASSERT_STREQ("1.2345678901234567E0", d2s(1.2345678901234567)); | |
104 | ||
105 | // Test 32-bit chunking | |
106 | ASSERT_STREQ("4.294967294E0", d2s(4.294967294)); // 2^32 - 2 | |
107 | ASSERT_STREQ("4.294967295E0", d2s(4.294967295)); // 2^32 - 1 | |
108 | ASSERT_STREQ("4.294967296E0", d2s(4.294967296)); // 2^32 | |
109 | ASSERT_STREQ("4.294967297E0", d2s(4.294967297)); // 2^32 + 1 | |
110 | ASSERT_STREQ("4.294967298E0", d2s(4.294967298)); // 2^32 + 2 | |
111 | } | |
112 | ||
113 | // Test min, max shift values in shiftright128 | |
114 | TEST(D2sTest, MinMaxShift) { | |
115 | const uint64_t maxMantissa = ((std::uint64_t)1 << 53) - 1; | |
116 | ||
117 | // 32-bit opt-size=0: 49 <= dist <= 50 | |
118 | // 32-bit opt-size=1: 30 <= dist <= 50 | |
119 | // 64-bit opt-size=0: 50 <= dist <= 50 | |
120 | // 64-bit opt-size=1: 30 <= dist <= 50 | |
121 | ASSERT_STREQ("1.7800590868057611E-307", d2s(ieeeParts2Double(false, 4, 0))); | |
122 | // 32-bit opt-size=0: 49 <= dist <= 49 | |
123 | // 32-bit opt-size=1: 28 <= dist <= 49 | |
124 | // 64-bit opt-size=0: 50 <= dist <= 50 | |
125 | // 64-bit opt-size=1: 28 <= dist <= 50 | |
126 | ASSERT_STREQ("2.8480945388892175E-306", d2s(ieeeParts2Double(false, 6, maxMantissa))); | |
127 | // 32-bit opt-size=0: 52 <= dist <= 53 | |
128 | // 32-bit opt-size=1: 2 <= dist <= 53 | |
129 | // 64-bit opt-size=0: 53 <= dist <= 53 | |
130 | // 64-bit opt-size=1: 2 <= dist <= 53 | |
131 | ASSERT_STREQ("2.446494580089078E-296", d2s(ieeeParts2Double(false, 41, 0))); | |
132 | // 32-bit opt-size=0: 52 <= dist <= 52 | |
133 | // 32-bit opt-size=1: 2 <= dist <= 52 | |
134 | // 64-bit opt-size=0: 53 <= dist <= 53 | |
135 | // 64-bit opt-size=1: 2 <= dist <= 53 | |
136 | ASSERT_STREQ("4.8929891601781557E-296", d2s(ieeeParts2Double(false, 40, maxMantissa))); | |
137 | ||
138 | // 32-bit opt-size=0: 57 <= dist <= 58 | |
139 | // 32-bit opt-size=1: 57 <= dist <= 58 | |
140 | // 64-bit opt-size=0: 58 <= dist <= 58 | |
141 | // 64-bit opt-size=1: 58 <= dist <= 58 | |
142 | ASSERT_STREQ("1.8014398509481984E16", d2s(ieeeParts2Double(false, 1077, 0))); | |
143 | // 32-bit opt-size=0: 57 <= dist <= 57 | |
144 | // 32-bit opt-size=1: 57 <= dist <= 57 | |
145 | // 64-bit opt-size=0: 58 <= dist <= 58 | |
146 | // 64-bit opt-size=1: 58 <= dist <= 58 | |
147 | ASSERT_STREQ("3.6028797018963964E16", d2s(ieeeParts2Double(false, 1076, maxMantissa))); | |
148 | // 32-bit opt-size=0: 51 <= dist <= 52 | |
149 | // 32-bit opt-size=1: 51 <= dist <= 59 | |
150 | // 64-bit opt-size=0: 52 <= dist <= 52 | |
151 | // 64-bit opt-size=1: 52 <= dist <= 59 | |
152 | ASSERT_STREQ("2.900835519859558E-216", d2s(ieeeParts2Double(false, 307, 0))); | |
153 | // 32-bit opt-size=0: 51 <= dist <= 51 | |
154 | // 32-bit opt-size=1: 51 <= dist <= 59 | |
155 | // 64-bit opt-size=0: 52 <= dist <= 52 | |
156 | // 64-bit opt-size=1: 52 <= dist <= 59 | |
157 | ASSERT_STREQ("5.801671039719115E-216", d2s(ieeeParts2Double(false, 306, maxMantissa))); | |
158 | ||
159 | // https://github.com/ulfjack/ryu/commit/19e44d16d80236f5de25800f56d82606d1be00b9#commitcomment-30146483 | |
160 | // 32-bit opt-size=0: 49 <= dist <= 49 | |
161 | // 32-bit opt-size=1: 44 <= dist <= 49 | |
162 | // 64-bit opt-size=0: 50 <= dist <= 50 | |
163 | // 64-bit opt-size=1: 44 <= dist <= 50 | |
164 | ASSERT_STREQ("3.196104012172126E-27", d2s(ieeeParts2Double(false, 934, 0x000FA7161A4D6E0Cu))); | |
165 | } | |
166 | ||
167 | TEST(D2sTest, SmallIntegers) { | |
168 | ASSERT_STREQ("9.007199254740991E15", d2s(9007199254740991.0)); // 2^53-1 | |
169 | ASSERT_STREQ("9.007199254740992E15", d2s(9007199254740992.0)); // 2^53 | |
170 | ||
171 | ASSERT_STREQ("1E0", d2s(1.0e+0)); | |
172 | ASSERT_STREQ("1.2E1", d2s(1.2e+1)); | |
173 | ASSERT_STREQ("1.23E2", d2s(1.23e+2)); | |
174 | ASSERT_STREQ("1.234E3", d2s(1.234e+3)); | |
175 | ASSERT_STREQ("1.2345E4", d2s(1.2345e+4)); | |
176 | ASSERT_STREQ("1.23456E5", d2s(1.23456e+5)); | |
177 | ASSERT_STREQ("1.234567E6", d2s(1.234567e+6)); | |
178 | ASSERT_STREQ("1.2345678E7", d2s(1.2345678e+7)); | |
179 | ASSERT_STREQ("1.23456789E8", d2s(1.23456789e+8)); | |
180 | ASSERT_STREQ("1.23456789E9", d2s(1.23456789e+9)); | |
181 | ASSERT_STREQ("1.234567895E9", d2s(1.234567895e+9)); | |
182 | ASSERT_STREQ("1.2345678901E10", d2s(1.2345678901e+10)); | |
183 | ASSERT_STREQ("1.23456789012E11", d2s(1.23456789012e+11)); | |
184 | ASSERT_STREQ("1.234567890123E12", d2s(1.234567890123e+12)); | |
185 | ASSERT_STREQ("1.2345678901234E13", d2s(1.2345678901234e+13)); | |
186 | ASSERT_STREQ("1.23456789012345E14", d2s(1.23456789012345e+14)); | |
187 | ASSERT_STREQ("1.234567890123456E15", d2s(1.234567890123456e+15)); | |
188 | ||
189 | // 10^i | |
190 | ASSERT_STREQ("1E0", d2s(1.0e+0)); | |
191 | ASSERT_STREQ("1E1", d2s(1.0e+1)); | |
192 | ASSERT_STREQ("1E2", d2s(1.0e+2)); | |
193 | ASSERT_STREQ("1E3", d2s(1.0e+3)); | |
194 | ASSERT_STREQ("1E4", d2s(1.0e+4)); | |
195 | ASSERT_STREQ("1E5", d2s(1.0e+5)); | |
196 | ASSERT_STREQ("1E6", d2s(1.0e+6)); | |
197 | ASSERT_STREQ("1E7", d2s(1.0e+7)); | |
198 | ASSERT_STREQ("1E8", d2s(1.0e+8)); | |
199 | ASSERT_STREQ("1E9", d2s(1.0e+9)); | |
200 | ASSERT_STREQ("1E10", d2s(1.0e+10)); | |
201 | ASSERT_STREQ("1E11", d2s(1.0e+11)); | |
202 | ASSERT_STREQ("1E12", d2s(1.0e+12)); | |
203 | ASSERT_STREQ("1E13", d2s(1.0e+13)); | |
204 | ASSERT_STREQ("1E14", d2s(1.0e+14)); | |
205 | ASSERT_STREQ("1E15", d2s(1.0e+15)); | |
206 | ||
207 | // 10^15 + 10^i | |
208 | ASSERT_STREQ("1.000000000000001E15", d2s(1.0e+15 + 1.0e+0)); | |
209 | ASSERT_STREQ("1.00000000000001E15", d2s(1.0e+15 + 1.0e+1)); | |
210 | ASSERT_STREQ("1.0000000000001E15", d2s(1.0e+15 + 1.0e+2)); | |
211 | ASSERT_STREQ("1.000000000001E15", d2s(1.0e+15 + 1.0e+3)); | |
212 | ASSERT_STREQ("1.00000000001E15", d2s(1.0e+15 + 1.0e+4)); | |
213 | ASSERT_STREQ("1.0000000001E15", d2s(1.0e+15 + 1.0e+5)); | |
214 | ASSERT_STREQ("1.000000001E15", d2s(1.0e+15 + 1.0e+6)); | |
215 | ASSERT_STREQ("1.00000001E15", d2s(1.0e+15 + 1.0e+7)); | |
216 | ASSERT_STREQ("1.0000001E15", d2s(1.0e+15 + 1.0e+8)); | |
217 | ASSERT_STREQ("1.000001E15", d2s(1.0e+15 + 1.0e+9)); | |
218 | ASSERT_STREQ("1.00001E15", d2s(1.0e+15 + 1.0e+10)); | |
219 | ASSERT_STREQ("1.0001E15", d2s(1.0e+15 + 1.0e+11)); | |
220 | ASSERT_STREQ("1.001E15", d2s(1.0e+15 + 1.0e+12)); | |
221 | ASSERT_STREQ("1.01E15", d2s(1.0e+15 + 1.0e+13)); | |
222 | ASSERT_STREQ("1.1E15", d2s(1.0e+15 + 1.0e+14)); | |
223 | ||
224 | // Largest power of 2 <= 10^(i+1) | |
225 | ASSERT_STREQ("8E0", d2s(8.0)); | |
226 | ASSERT_STREQ("6.4E1", d2s(64.0)); | |
227 | ASSERT_STREQ("5.12E2", d2s(512.0)); | |
228 | ASSERT_STREQ("8.192E3", d2s(8192.0)); | |
229 | ASSERT_STREQ("6.5536E4", d2s(65536.0)); | |
230 | ASSERT_STREQ("5.24288E5", d2s(524288.0)); | |
231 | ASSERT_STREQ("8.388608E6", d2s(8388608.0)); | |
232 | ASSERT_STREQ("6.7108864E7", d2s(67108864.0)); | |
233 | ASSERT_STREQ("5.36870912E8", d2s(536870912.0)); | |
234 | ASSERT_STREQ("8.589934592E9", d2s(8589934592.0)); | |
235 | ASSERT_STREQ("6.8719476736E10", d2s(68719476736.0)); | |
236 | ASSERT_STREQ("5.49755813888E11", d2s(549755813888.0)); | |
237 | ASSERT_STREQ("8.796093022208E12", d2s(8796093022208.0)); | |
238 | ASSERT_STREQ("7.0368744177664E13", d2s(70368744177664.0)); | |
239 | ASSERT_STREQ("5.62949953421312E14", d2s(562949953421312.0)); | |
240 | ASSERT_STREQ("9.007199254740992E15", d2s(9007199254740992.0)); | |
241 | ||
242 | // 1000 * (Largest power of 2 <= 10^(i+1)) | |
243 | ASSERT_STREQ("8E3", d2s(8.0e+3)); | |
244 | ASSERT_STREQ("6.4E4", d2s(64.0e+3)); | |
245 | ASSERT_STREQ("5.12E5", d2s(512.0e+3)); | |
246 | ASSERT_STREQ("8.192E6", d2s(8192.0e+3)); | |
247 | ASSERT_STREQ("6.5536E7", d2s(65536.0e+3)); | |
248 | ASSERT_STREQ("5.24288E8", d2s(524288.0e+3)); | |
249 | ASSERT_STREQ("8.388608E9", d2s(8388608.0e+3)); | |
250 | ASSERT_STREQ("6.7108864E10", d2s(67108864.0e+3)); | |
251 | ASSERT_STREQ("5.36870912E11", d2s(536870912.0e+3)); | |
252 | ASSERT_STREQ("8.589934592E12", d2s(8589934592.0e+3)); | |
253 | ASSERT_STREQ("6.8719476736E13", d2s(68719476736.0e+3)); | |
254 | ASSERT_STREQ("5.49755813888E14", d2s(549755813888.0e+3)); | |
255 | ASSERT_STREQ("8.796093022208E15", d2s(8796093022208.0e+3)); | |
256 | } | |
257 | ||
258 | } // ryu | |
259 | ||
260 | } // detail | |
261 | BOOST_JSON_NS_END |