authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2022-05-02 22:45:06+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2022-05-03 16:46:40+12:00
log2085a4af5654a74f2a5d8ac1fa7934a3663bf3a0
treeaa5e813758dba7fbcbcb6e9e966e0b6474f72478
parent098bee0e5657bb6dcd92b2b2fa8056ffce893ffc

add new float-parser based on eisel-lemire algorithm

The previous float-parsing method was lacking in a lot of areas. This commit introduces a state-of-the art implementation that is both accurate and fast to std. Code is derived from working repo https://github.com/tiehuis/zig-parsefloat. This includes more test-cases and performance numbers that are present in this commit. * Accuracy The primary testing regime has been using test-data found at https://github.com/tiehuis/parse-number-fxx-test-data. This is a fork of upstream with support for f128 test-cases added. This data has been verified against other independent implementations and represents accurate round-to-even IEEE-754 floating point semantics. * Performance Compared to the existing parseFloat implementation there is ~5-10x performance improvement using the above corpus. (f128 parsing excluded in below measurements). ** Old $ time ./test_all_fxx_data 3520298/5296694 succeeded (1776396 fail) ________________________________________________________ Executed in 28.68 secs fish external usr time 28.48 secs 0.00 micros 28.48 secs sys time 0.08 secs 694.00 micros 0.08 secs ** This Implementation $ time ./test_all_fxx_data 5296693/5296694 succeeded (1 fail) ________________________________________________________ Executed in 4.54 secs fish external usr time 4.37 secs 515.00 micros 4.37 secs sys time 0.10 secs 171.00 micros 0.10 secs Further performance numbers can be seen using the https://github.com/tiehuis/simple_fastfloat_benchmark/ repository, which compares against some other well-known string-to-float conversion functions. A breakdown can be found here: https://github.com/tiehuis/zig-parsefloat/blob/0d9f020f1a37ca88bf889703b397c1c41779f090/PERFORMANCE.md#commit-b15406a0d2e18b50a4b62fceb5a6a3bb60ca5706 In summary, we are within 20% of the C++ reference implementation and have about ~600-700MB/s throughput on a Intel I5-6500 3.5Ghz. * F128 Support Finally, f128 is now completely supported with full accuracy. This does use a slower path which is possible to improve in future. * Behavioural Changes There are a few behavioural changes to note. - `parseHexFloat` is now redundant and these are now supported directly in `parseFloat`. - We implement round-to-even in all parsing routines. This is as specified by IEEE-754. Previous code used different rounding mechanisms (standard was round-to-zero, hex-parsing looked to use round-up) so there may be subtle differences. Closes #2207. Fixes #11169.

13 files changed, 2497 insertions(+), 736 deletions(-)

lib/std/fmt.zig+1-1
......@@ -1837,8 +1837,8 @@ test "parseUnsigned" {
18371837}
18381838
18391839pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
1840pub const parseHexFloat = @compileError("deprecated; use `parseFloat`");
18401841pub const ParseFloatError = @import("fmt/parse_float.zig").ParseFloatError;
1841pub const parseHexFloat = @import("fmt/parse_hex_float.zig").parseHexFloat;
18421842
18431843test {
18441844 _ = parseFloat;
lib/std/fmt/parse_float.zig+111-388
......@@ -1,386 +1,18 @@
1// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.
2
3// MIT License
4//
5// Copyright (c) 2016 Grzegorz Kraszewski
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to deal
9// in the Software without restriction, including without limitation the rights
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in all
15// copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23// SOFTWARE.
24//
25
26// Be aware that this implementation has the following limitations:
27//
28// - Is not round-trip accurate for all values
29// - Only supports round-to-zero
30// - Does not handle denormals
1pub const parseFloat = @import("parse_float/parse_float.zig").parseFloat;
2pub const ParseFloatError = @import("parse_float/parse_float.zig").ParseFloatError;
313
324const std = @import("std");
33const ascii = std.ascii;
34
35// The mantissa field in FloatRepr is 64bit wide and holds only 19 digits
36// without overflowing
37const max_digits = 19;
38
39const f64_plus_zero: u64 = 0x0000000000000000;
40const f64_minus_zero: u64 = 0x8000000000000000;
41const f64_plus_infinity: u64 = 0x7FF0000000000000;
42const f64_minus_infinity: u64 = 0xFFF0000000000000;
43
44const Z96 = struct {
45 d0: u32,
46 d1: u32,
47 d2: u32,
48
49 // d = s >> 1
50 inline fn shiftRight1(d: *Z96, s: Z96) void {
51 d.d0 = (s.d0 >> 1) | ((s.d1 & 1) << 31);
52 d.d1 = (s.d1 >> 1) | ((s.d2 & 1) << 31);
53 d.d2 = s.d2 >> 1;
54 }
55
56 // d = s << 1
57 inline fn shiftLeft1(d: *Z96, s: Z96) void {
58 d.d2 = (s.d2 << 1) | ((s.d1 & (1 << 31)) >> 31);
59 d.d1 = (s.d1 << 1) | ((s.d0 & (1 << 31)) >> 31);
60 d.d0 = s.d0 << 1;
61 }
62
63 // d += s
64 inline fn add(d: *Z96, s: Z96) void {
65 var w = @as(u64, d.d0) + @as(u64, s.d0);
66 d.d0 = @truncate(u32, w);
67
68 w >>= 32;
69 w += @as(u64, d.d1) + @as(u64, s.d1);
70 d.d1 = @truncate(u32, w);
71
72 w >>= 32;
73 w += @as(u64, d.d2) + @as(u64, s.d2);
74 d.d2 = @truncate(u32, w);
75 }
76
77 // d -= s
78 inline fn sub(d: *Z96, s: Z96) void {
79 var w = @as(u64, d.d0) -% @as(u64, s.d0);
80 d.d0 = @truncate(u32, w);
81
82 w >>= 32;
83 w += @as(u64, d.d1) -% @as(u64, s.d1);
84 d.d1 = @truncate(u32, w);
85
86 w >>= 32;
87 w += @as(u64, d.d2) -% @as(u64, s.d2);
88 d.d2 = @truncate(u32, w);
89 }
90};
91
92const FloatRepr = struct {
93 negative: bool,
94 exponent: i32,
95 mantissa: u64,
96};
97
98fn convertRepr(comptime T: type, n: FloatRepr) T {
99 const mask28: u32 = 0xf << 28;
100
101 var s: Z96 = undefined;
102 var q: Z96 = undefined;
103 var r: Z96 = undefined;
104
105 s.d0 = @truncate(u32, n.mantissa);
106 s.d1 = @truncate(u32, n.mantissa >> 32);
107 s.d2 = 0;
108
109 var binary_exponent: i32 = 92;
110 var exp = n.exponent;
111
112 while (exp > 0) : (exp -= 1) {
113 q.shiftLeft1(s); // q = p << 1
114 r.shiftLeft1(q); // r = p << 2
115 s.shiftLeft1(r); // p = p << 3
116 s.add(q); // p = (p << 3) + (p << 1)
117
118 while (s.d2 & mask28 != 0) {
119 q.shiftRight1(s);
120 binary_exponent += 1;
121 s = q;
122 }
123 }
124
125 while (exp < 0) {
126 while (s.d2 & (1 << 31) == 0) {
127 q.shiftLeft1(s);
128 binary_exponent -= 1;
129 s = q;
130 }
131
132 q.d2 = s.d2 / 10;
133 r.d1 = s.d2 % 10;
134 r.d2 = (s.d1 >> 8) | (r.d1 << 24);
135 q.d1 = r.d2 / 10;
136 r.d1 = r.d2 % 10;
137 r.d2 = ((s.d1 & 0xff) << 16) | (s.d0 >> 16) | (r.d1 << 24);
138 r.d0 = r.d2 / 10;
139 r.d1 = r.d2 % 10;
140 q.d1 = (q.d1 << 8) | ((r.d0 & 0x00ff0000) >> 16);
141 q.d0 = r.d0 << 16;
142 r.d2 = (s.d0 *% 0xffff) | (r.d1 << 16);
143 q.d0 |= r.d2 / 10;
144 s = q;
145
146 exp += 1;
147 }
148
149 if (s.d0 != 0 or s.d1 != 0 or s.d2 != 0) {
150 while (s.d2 & mask28 == 0) {
151 q.shiftLeft1(s);
152 binary_exponent -= 1;
153 s = q;
154 }
155 }
156
157 binary_exponent += 1023;
158
159 const repr: u64 = blk: {
160 if (binary_exponent > 2046) {
161 break :blk if (n.negative) f64_minus_infinity else f64_plus_infinity;
162 } else if (binary_exponent < 1) {
163 break :blk if (n.negative) f64_minus_zero else f64_plus_zero;
164 } else if (s.d2 != 0) {
165 const binexs2 = @intCast(u64, binary_exponent) << 52;
166 const rr = (@as(u64, s.d2 & ~mask28) << 24) | ((@as(u64, s.d1) + 128) >> 8) | binexs2;
167 break :blk if (n.negative) rr | (1 << 63) else rr;
168 } else {
169 break :blk 0;
170 }
171 };
172
173 const f = @bitCast(f64, repr);
174 return @floatCast(T, f);
175}
176
177const State = enum {
178 MaybeSign,
179 LeadingMantissaZeros,
180 LeadingFractionalZeros,
181 MantissaIntegral,
182 MantissaFractional,
183 ExponentSign,
184 LeadingExponentZeros,
185 Exponent,
186};
187
188const ParseResult = enum {
189 Ok,
190 PlusZero,
191 MinusZero,
192 PlusInf,
193 MinusInf,
194};
195
196fn parseRepr(s: []const u8, n: *FloatRepr) !ParseResult {
197 var digit_index: usize = 0;
198 var negative_exp = false;
199 var exponent: i32 = 0;
200
201 var state = State.MaybeSign;
5const math = std.math;
6const testing = std.testing;
7const expect = testing.expect;
8const expectEqual = testing.expectEqual;
9const expectError = testing.expectError;
10const approxEqAbs = std.math.approxEqAbs;
11const epsilon = 1e-7;
20212
203 var i: usize = 0;
204 while (i < s.len) {
205 const c = s[i];
206
207 switch (state) {
208 .MaybeSign => {
209 state = .LeadingMantissaZeros;
210
211 if (c == '+') {
212 i += 1;
213 } else if (c == '-') {
214 n.negative = true;
215 i += 1;
216 } else if (ascii.isDigit(c) or c == '.') {
217 // continue
218 } else {
219 return error.InvalidCharacter;
220 }
221 },
222 .LeadingMantissaZeros => {
223 if (c == '0') {
224 i += 1;
225 } else if (c == '.') {
226 i += 1;
227 state = .LeadingFractionalZeros;
228 } else if (c == '_') {
229 i += 1;
230 } else {
231 state = .MantissaIntegral;
232 }
233 },
234 .LeadingFractionalZeros => {
235 if (c == '0') {
236 i += 1;
237 if (n.exponent > std.math.minInt(i32)) {
238 n.exponent -= 1;
239 }
240 } else {
241 state = .MantissaFractional;
242 }
243 },
244 .MantissaIntegral => {
245 if (ascii.isDigit(c)) {
246 if (digit_index < max_digits) {
247 n.mantissa *%= 10;
248 n.mantissa += c - '0';
249 digit_index += 1;
250 } else if (n.exponent < std.math.maxInt(i32)) {
251 n.exponent += 1;
252 }
253
254 i += 1;
255 } else if (c == '.') {
256 i += 1;
257 state = .MantissaFractional;
258 } else if (c == '_') {
259 i += 1;
260 } else {
261 state = .MantissaFractional;
262 }
263 },
264 .MantissaFractional => {
265 if (ascii.isDigit(c)) {
266 if (digit_index < max_digits) {
267 n.mantissa *%= 10;
268 n.mantissa += c - '0';
269 n.exponent -%= 1;
270 digit_index += 1;
271 }
272
273 i += 1;
274 } else if (c == 'e' or c == 'E') {
275 i += 1;
276 state = .ExponentSign;
277 } else if (c == '_') {
278 i += 1;
279 } else {
280 state = .ExponentSign;
281 }
282 },
283 .ExponentSign => {
284 if (c == '+') {
285 i += 1;
286 } else if (c == '_') {
287 return error.InvalidCharacter;
288 } else if (c == '-') {
289 negative_exp = true;
290 i += 1;
291 }
292
293 state = .LeadingExponentZeros;
294 },
295 .LeadingExponentZeros => {
296 if (c == '0') {
297 i += 1;
298 } else if (c == '_') {
299 i += 1;
300 } else {
301 state = .Exponent;
302 }
303 },
304 .Exponent => {
305 if (ascii.isDigit(c)) {
306 if (exponent < std.math.maxInt(i32) / 10) {
307 exponent *= 10;
308 exponent += @intCast(i32, c - '0');
309 }
310
311 i += 1;
312 } else if (c == '_') {
313 i += 1;
314 } else {
315 return error.InvalidCharacter;
316 }
317 },
318 }
319 }
320
321 if (negative_exp) exponent = -exponent;
322 n.exponent += exponent;
323
324 if (n.mantissa == 0) {
325 return if (n.negative) .MinusZero else .PlusZero;
326 } else if (n.exponent > 309) {
327 return if (n.negative) .MinusInf else .PlusInf;
328 } else if (n.exponent < -328) {
329 return if (n.negative) .MinusZero else .PlusZero;
330 }
331
332 return .Ok;
333}
334
335fn caseInEql(a: []const u8, b: []const u8) bool {
336 if (a.len != b.len) return false;
337
338 for (a) |_, i| {
339 if (ascii.toUpper(a[i]) != ascii.toUpper(b[i])) {
340 return false;
341 }
342 }
343
344 return true;
345}
346
347pub const ParseFloatError = error{InvalidCharacter};
348
349pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T {
350 if (s.len == 0 or (s.len == 1 and (s[0] == '+' or s[0] == '-'))) {
351 return error.InvalidCharacter;
352 }
353
354 if (caseInEql(s, "nan")) {
355 return std.math.nan(T);
356 } else if (caseInEql(s, "inf") or caseInEql(s, "+inf")) {
357 return std.math.inf(T);
358 } else if (caseInEql(s, "-inf")) {
359 return -std.math.inf(T);
360 }
361
362 var r = FloatRepr{
363 .negative = false,
364 .exponent = 0,
365 .mantissa = 0,
366 };
367
368 return switch (try parseRepr(s, &r)) {
369 .Ok => convertRepr(T, r),
370 .PlusZero => 0.0,
371 .MinusZero => -@as(T, 0.0),
372 .PlusInf => std.math.inf(T),
373 .MinusInf => -std.math.inf(T),
374 };
375}
13// See https://github.com/tiehuis/parse-number-fxx-test-data for a wider-selection of test-data.
37614
37715test "fmt.parseFloat" {
378 const testing = std.testing;
379 const expect = testing.expect;
380 const expectEqual = testing.expectEqual;
381 const approxEqAbs = std.math.approxEqAbs;
382 const epsilon = 1e-7;
383
38416 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
38517 const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
38618
......@@ -405,8 +37,8 @@ test "fmt.parseFloat" {
40537 try expect(approxEqAbs(T, try parseFloat(T, "3.141"), 3.141, epsilon));
40638 try expect(approxEqAbs(T, try parseFloat(T, "-3.141"), -3.141, epsilon));
40739
408 try expectEqual(try parseFloat(T, "1e-700"), 0);
409 try expectEqual(try parseFloat(T, "1e+700"), std.math.inf(T));
40 try expectEqual(try parseFloat(T, "1e-5000"), 0);
41 try expectEqual(try parseFloat(T, "1e+5000"), std.math.inf(T));
41042
41143 try expectEqual(@bitCast(Z, try parseFloat(T, "nAn")), @bitCast(Z, std.math.nan(T)));
41244 try expectEqual(try parseFloat(T, "inF"), std.math.inf(T));
......@@ -415,14 +47,105 @@ test "fmt.parseFloat" {
41547 try expectEqual(try parseFloat(T, "0.4e0066999999999999999999999999999999999999999999999999999"), std.math.inf(T));
41648 try expect(approxEqAbs(T, try parseFloat(T, "0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0"), @as(T, 123456.789000e10), epsilon));
41749
418 if (T != f16) {
419 try expect(approxEqAbs(T, try parseFloat(T, "1e-2"), 0.01, epsilon));
420 try expect(approxEqAbs(T, try parseFloat(T, "1234e-2"), 12.34, epsilon));
50 // underscore rule is simple and reduces to "can only occur between two digits" and multiple are not supported.
51 try expectError(error.InvalidCharacter, parseFloat(T, "0123456.789000e_0010")); // cannot occur immediately after exponent
52 try expectError(error.InvalidCharacter, parseFloat(T, "_0123456.789000e0010")); // cannot occur before any digits
53 try expectError(error.InvalidCharacter, parseFloat(T, "0__123456.789000e_0010")); // cannot occur twice in a row
54 try expectError(error.InvalidCharacter, parseFloat(T, "0123456_.789000e0010")); // cannot occur before decimal point
55 try expectError(error.InvalidCharacter, parseFloat(T, "0123456.789000e0010_")); // cannot occur at end of number
56
57 try expect(approxEqAbs(T, try parseFloat(T, "1e-2"), 0.01, epsilon));
58 try expect(approxEqAbs(T, try parseFloat(T, "1234e-2"), 12.34, epsilon));
42159
422 try expect(approxEqAbs(T, try parseFloat(T, "123142.1"), 123142.1, epsilon));
423 try expect(approxEqAbs(T, try parseFloat(T, "-123142.1124"), @as(T, -123142.1124), epsilon));
424 try expect(approxEqAbs(T, try parseFloat(T, "0.7062146892655368"), @as(T, 0.7062146892655368), epsilon));
425 try expect(approxEqAbs(T, try parseFloat(T, "2.71828182845904523536"), @as(T, 2.718281828459045), epsilon));
426 }
60 try expect(approxEqAbs(T, try parseFloat(T, "123142.1"), 123142.1, epsilon));
61 try expect(approxEqAbs(T, try parseFloat(T, "-123142.1124"), @as(T, -123142.1124), epsilon));
62 try expect(approxEqAbs(T, try parseFloat(T, "0.7062146892655368"), @as(T, 0.7062146892655368), epsilon));
63 try expect(approxEqAbs(T, try parseFloat(T, "2.71828182845904523536"), @as(T, 2.718281828459045), epsilon));
42764 }
42865}
66
67test "fmt.parseFloat #11169" {
68 try expectEqual(try parseFloat(f128, "9007199254740993.0"), 9007199254740993.0);
69}
70
71test "fmt.parseFloat hex.special" {
72 try testing.expect(math.isNan(try parseFloat(f32, "nAn")));
73 try testing.expect(math.isPositiveInf(try parseFloat(f32, "iNf")));
74 try testing.expect(math.isPositiveInf(try parseFloat(f32, "+Inf")));
75 try testing.expect(math.isNegativeInf(try parseFloat(f32, "-iNf")));
76}
77test "fmt.parseFloat hex.zero" {
78 try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "0x0"));
79 try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "-0x0"));
80 try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "0x0p42"));
81 try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "-0x0.00000p42"));
82 try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "0x0.00000p666"));
83}
84
85test "fmt.parseFloat hex.f16" {
86 try testing.expectEqual(try parseFloat(f16, "0x1p0"), 1.0);
87 try testing.expectEqual(try parseFloat(f16, "-0x1p-1"), -0.5);
88 try testing.expectEqual(try parseFloat(f16, "0x10p+10"), 16384.0);
89 try testing.expectEqual(try parseFloat(f16, "0x10p-10"), 0.015625);
90 // Max normalized value.
91 try testing.expectEqual(try parseFloat(f16, "0x1.ffcp+15"), math.floatMax(f16));
92 try testing.expectEqual(try parseFloat(f16, "-0x1.ffcp+15"), -math.floatMax(f16));
93 // Min normalized value.
94 try testing.expectEqual(try parseFloat(f16, "0x1p-14"), math.floatMin(f16));
95 try testing.expectEqual(try parseFloat(f16, "-0x1p-14"), -math.floatMin(f16));
96 // Min denormal value.
97 try testing.expectEqual(try parseFloat(f16, "0x1p-24"), math.floatTrueMin(f16));
98 try testing.expectEqual(try parseFloat(f16, "-0x1p-24"), -math.floatTrueMin(f16));
99}
100
101test "fmt.parseFloat hex.f32" {
102 try testing.expectEqual(try parseFloat(f32, "0x1p0"), 1.0);
103 try testing.expectEqual(try parseFloat(f32, "-0x1p-1"), -0.5);
104 try testing.expectEqual(try parseFloat(f32, "0x10p+10"), 16384.0);
105 try testing.expectEqual(try parseFloat(f32, "0x10p-10"), 0.015625);
106 try testing.expectEqual(try parseFloat(f32, "0x0.ffffffp128"), 0x0.ffffffp128);
107 try testing.expectEqual(try parseFloat(f32, "0x0.1234570p-125"), 0x0.1234570p-125);
108 // Max normalized value.
109 try testing.expectEqual(try parseFloat(f32, "0x1.fffffeP+127"), math.floatMax(f32));
110 try testing.expectEqual(try parseFloat(f32, "-0x1.fffffeP+127"), -math.floatMax(f32));
111 // Min normalized value.
112 try testing.expectEqual(try parseFloat(f32, "0x1p-126"), math.floatMin(f32));
113 try testing.expectEqual(try parseFloat(f32, "-0x1p-126"), -math.floatMin(f32));
114 // Min denormal value.
115 try testing.expectEqual(try parseFloat(f32, "0x1P-149"), math.floatTrueMin(f32));
116 try testing.expectEqual(try parseFloat(f32, "-0x1P-149"), -math.floatTrueMin(f32));
117}
118
119test "fmt.parseFloat hex.f64" {
120 try testing.expectEqual(try parseFloat(f64, "0x1p0"), 1.0);
121 try testing.expectEqual(try parseFloat(f64, "-0x1p-1"), -0.5);
122 try testing.expectEqual(try parseFloat(f64, "0x10p+10"), 16384.0);
123 try testing.expectEqual(try parseFloat(f64, "0x10p-10"), 0.015625);
124 // Max normalized value.
125 try testing.expectEqual(try parseFloat(f64, "0x1.fffffffffffffp+1023"), math.floatMax(f64));
126 try testing.expectEqual(try parseFloat(f64, "-0x1.fffffffffffffp1023"), -math.floatMax(f64));
127 // Min normalized value.
128 try testing.expectEqual(try parseFloat(f64, "0x1p-1022"), math.floatMin(f64));
129 try testing.expectEqual(try parseFloat(f64, "-0x1p-1022"), -math.floatMin(f64));
130 // Min denormalized value.
131 //try testing.expectEqual(try parseFloat(f64, "0x1p-1074"), math.floatTrueMin(f64));
132 try testing.expectEqual(try parseFloat(f64, "-0x1p-1074"), -math.floatTrueMin(f64));
133}
134test "fmt.parseFloat hex.f128" {
135 try testing.expectEqual(try parseFloat(f128, "0x1p0"), 1.0);
136 try testing.expectEqual(try parseFloat(f128, "-0x1p-1"), -0.5);
137 try testing.expectEqual(try parseFloat(f128, "0x10p+10"), 16384.0);
138 try testing.expectEqual(try parseFloat(f128, "0x10p-10"), 0.015625);
139 // Max normalized value.
140 try testing.expectEqual(try parseFloat(f128, "0xf.fffffffffffffffffffffffffff8p+16380"), math.floatMax(f128));
141 try testing.expectEqual(try parseFloat(f128, "-0xf.fffffffffffffffffffffffffff8p+16380"), -math.floatMax(f128));
142 // Min normalized value.
143 try testing.expectEqual(try parseFloat(f128, "0x1p-16382"), math.floatMin(f128));
144 try testing.expectEqual(try parseFloat(f128, "-0x1p-16382"), -math.floatMin(f128));
145 // // Min denormalized value.
146 try testing.expectEqual(try parseFloat(f128, "0x1p-16494"), math.floatTrueMin(f128));
147 try testing.expectEqual(try parseFloat(f128, "-0x1p-16494"), -math.floatTrueMin(f128));
148
149 // NOTE: We are performing round-to-even. Previous behavior was round-up.
150 // try testing.expectEqual(try parseFloat(f128, "0x1.edcb34a235253948765432134674fp-1"), 0x1.edcb34a235253948765432134674fp-1);
151}
lib/std/fmt/parse_float/FloatInfo.zig created+131
......@@ -0,0 +1,131 @@
1const std = @import("std");
2const Self = @This();
3
4// Minimum exponent that for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
5min_exponent_fast_path: comptime_int,
6
7// Maximum exponent that for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
8max_exponent_fast_path: comptime_int,
9
10// Maximum exponent that can be represented for a disguised-fast path case.
11// This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋`
12max_exponent_fast_path_disguised: comptime_int,
13
14// Maximum mantissa for the fast-path (`1 << 53` for f64).
15max_mantissa_fast_path: comptime_int,
16
17// Smallest decimal exponent for a non-zero value. Including subnormals.
18smallest_power_of_ten: comptime_int,
19
20// Largest decimal exponent for a non-infinite value.
21largest_power_of_ten: comptime_int,
22
23// The number of bits in the significand, *excluding* the hidden bit.
24mantissa_explicit_bits: comptime_int,
25
26// Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`.
27minimum_exponent: comptime_int,
28
29// Round-to-even only happens for negative values of q
30// when q ≥ −4 in the 64-bit case and when q ≥ −17 in
31// the 32-bitcase.
32//
33// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
34// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
35// 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10.
36//
37// When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64
38// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
39// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
40// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
41// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase).
42//
43// Thus we have that we only need to round ties to even when
44// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
45// (in the 32-bit case). In both cases,the power of five(5^|q|)
46// fits in a 64-bit word.
47min_exponent_round_to_even: comptime_int,
48max_exponent_round_to_even: comptime_int,
49
50// Largest exponent value `(1 << EXP_BITS) - 1`.
51infinite_power: comptime_int,
52
53// Following should compute based on derived calculations where possible.
54pub fn from(comptime T: type) Self {
55 return switch (T) {
56 f16 => .{
57 // Fast-Path
58 .min_exponent_fast_path = -4,
59 .max_exponent_fast_path = 4,
60 .max_exponent_fast_path_disguised = 7,
61 .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T),
62 // Slow + Eisel-Lemire
63 .mantissa_explicit_bits = std.math.floatMantissaBits(T),
64 .infinite_power = 0x1f,
65 // Eisel-Lemire
66 .smallest_power_of_ten = -26, // TODO: refine, fails one test
67 .largest_power_of_ten = 4,
68 .minimum_exponent = -15,
69 // w >= (2m+1) * 5^-q and w < 2^64
70 // => 2m+1 > 2^11
71 // => 2^11*5^-q < 2^64
72 // => 5^-q < 2^53
73 // => q >= -23
74 .min_exponent_round_to_even = -22,
75 .max_exponent_round_to_even = 5,
76 },
77 f32 => .{
78 // Fast-Path
79 .min_exponent_fast_path = -10,
80 .max_exponent_fast_path = 10,
81 .max_exponent_fast_path_disguised = 17,
82 .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T),
83 // Slow + Eisel-Lemire
84 .mantissa_explicit_bits = std.math.floatMantissaBits(T),
85 .infinite_power = 0xff,
86 // Eisel-Lemire
87 .smallest_power_of_ten = -65,
88 .largest_power_of_ten = 38,
89 .minimum_exponent = -127,
90 .min_exponent_round_to_even = -17,
91 .max_exponent_round_to_even = 10,
92 },
93 f64 => .{
94 // Fast-Path
95 .min_exponent_fast_path = -22,
96 .max_exponent_fast_path = 22,
97 .max_exponent_fast_path_disguised = 37,
98 .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T),
99 // Slow + Eisel-Lemire
100 .mantissa_explicit_bits = std.math.floatMantissaBits(T),
101 .infinite_power = 0x7ff,
102 // Eisel-Lemire
103 .smallest_power_of_ten = -342,
104 .largest_power_of_ten = 308,
105 .minimum_exponent = -1023,
106 .min_exponent_round_to_even = -4,
107 .max_exponent_round_to_even = 23,
108 },
109 f128 => .{
110 // Fast-Path
111 .min_exponent_fast_path = -48,
112 .max_exponent_fast_path = 48,
113 .max_exponent_fast_path_disguised = 82,
114 .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T),
115 // Slow + Eisel-Lemire
116 .mantissa_explicit_bits = std.math.floatMantissaBits(T),
117 .infinite_power = 0x7fff,
118 // Eisel-Lemire.
119 // NOTE: Not yet tested (no f128 eisel-lemire implementation)
120 .smallest_power_of_ten = -4966,
121 .largest_power_of_ten = 4932,
122 .minimum_exponent = -16382,
123 // 2^113 * 5^-q < 2^128
124 // 5^-q < 2^15
125 // => q >= -6
126 .min_exponent_round_to_even = -6,
127 .max_exponent_round_to_even = 49,
128 },
129 else => unreachable,
130 };
131}
lib/std/fmt/parse_float/FloatStream.zig created+137
......@@ -0,0 +1,137 @@
1//! A wrapper over a byte-slice, providing useful methods for parsing string floating point values.
2
3const std = @import("std");
4const FloatStream = @This();
5const common = @import("common.zig");
6
7slice: []const u8,
8offset: usize,
9underscore_count: usize,
10
11pub fn init(s: []const u8) FloatStream {
12 return .{ .slice = s, .offset = 0, .underscore_count = 0 };
13}
14
15// Returns the offset from the start *excluding* any underscores that were found.
16pub fn offsetTrue(self: FloatStream) usize {
17 return self.offset - self.underscore_count;
18}
19
20pub fn reset(self: *FloatStream) void {
21 self.offset = 0;
22 self.underscore_count = 0;
23}
24
25pub fn len(self: FloatStream) usize {
26 if (self.offset > self.slice.len) {
27 return 0;
28 }
29 return self.slice.len - self.offset;
30}
31
32pub fn hasLen(self: FloatStream, n: usize) bool {
33 return self.offset + n <= self.slice.len;
34}
35
36pub fn firstUnchecked(self: FloatStream) u8 {
37 return self.slice[self.offset];
38}
39
40pub fn first(self: FloatStream) ?u8 {
41 return if (self.hasLen(1))
42 return self.firstUnchecked()
43 else
44 null;
45}
46
47pub fn isEmpty(self: FloatStream) bool {
48 return !self.hasLen(1);
49}
50
51pub fn firstIs(self: FloatStream, c: u8) bool {
52 if (self.first()) |ok| {
53 return ok == c;
54 }
55 return false;
56}
57
58pub fn firstIsLower(self: FloatStream, c: u8) bool {
59 if (self.first()) |ok| {
60 return ok | 0x20 == c;
61 }
62 return false;
63}
64
65pub fn firstIs2(self: FloatStream, c1: u8, c2: u8) bool {
66 if (self.first()) |ok| {
67 return ok == c1 or ok == c2;
68 }
69 return false;
70}
71
72pub fn firstIs3(self: FloatStream, c1: u8, c2: u8, c3: u8) bool {
73 if (self.first()) |ok| {
74 return ok == c1 or ok == c2 or ok == c3;
75 }
76 return false;
77}
78
79pub fn firstIsDigit(self: FloatStream, comptime base: u8) bool {
80 comptime std.debug.assert(base == 10 or base == 16);
81
82 if (self.first()) |ok| {
83 return common.isDigit(ok, base);
84 }
85 return false;
86}
87
88pub fn advance(self: *FloatStream, n: usize) void {
89 self.offset += n;
90}
91
92pub fn skipChars(self: *FloatStream, c: u8) void {
93 while (self.firstIs(c)) : (self.advance(1)) {}
94}
95
96pub fn skipChars2(self: *FloatStream, c1: u8, c2: u8) void {
97 while (self.firstIs2(c1, c2)) : (self.advance(1)) {}
98}
99
100pub fn readU64Unchecked(self: FloatStream) u64 {
101 return std.mem.readIntSliceLittle(u64, self.slice[self.offset..]);
102}
103
104pub fn readU64(self: FloatStream) ?u64 {
105 if (self.hasLen(8)) {
106 return self.readU64Unchecked();
107 }
108 return null;
109}
110
111pub fn atUnchecked(self: *FloatStream, i: usize) u8 {
112 return self.slice[self.offset + i];
113}
114
115pub fn scanDigit(self: *FloatStream, comptime base: u8) ?u8 {
116 comptime std.debug.assert(base == 10 or base == 16);
117
118 retry: while (true) {
119 if (self.first()) |ok| {
120 if ('0' <= ok and ok <= '9') {
121 self.advance(1);
122 return ok - '0';
123 } else if (base == 16 and 'a' <= ok and ok <= 'f') {
124 self.advance(1);
125 return ok - 'a' + 10;
126 } else if (base == 16 and 'A' <= ok and ok <= 'F') {
127 self.advance(1);
128 return ok - 'A' + 10;
129 } else if (ok == '_') {
130 self.advance(1);
131 self.underscore_count += 1;
132 continue :retry;
133 }
134 }
135 return null;
136 }
137}
lib/std/fmt/parse_float/common.zig created+91
......@@ -0,0 +1,91 @@
1const std = @import("std");
2
3/// A custom N-bit floating point type, representing `f * 2^e`.
4/// e is biased, so it be directly shifted into the exponent bits.
5/// Negative exponent indicates an invalid result.
6pub fn BiasedFp(comptime T: type) type {
7 const MantissaT = mantissaType(T);
8
9 return struct {
10 const Self = @This();
11
12 /// The significant digits.
13 f: MantissaT,
14 /// The biased, binary exponent.
15 e: i32,
16
17 pub fn zero() Self {
18 return .{ .f = 0, .e = 0 };
19 }
20
21 pub fn zeroPow2(e: i32) Self {
22 return .{ .f = 0, .e = e };
23 }
24
25 pub fn inf(comptime FloatT: type) Self {
26 return .{ .f = 0, .e = (1 << std.math.floatExponentBits(FloatT)) - 1 };
27 }
28
29 pub fn eql(self: Self, other: Self) bool {
30 return self.f == other.f and self.e == other.e;
31 }
32
33 pub fn toFloat(self: Self, comptime FloatT: type, negative: bool) FloatT {
34 var word = self.f;
35 word |= @intCast(MantissaT, self.e) << std.math.floatMantissaBits(FloatT);
36 var f = floatFromUnsigned(FloatT, MantissaT, word);
37 if (negative) f = -f;
38 return f;
39 }
40 };
41}
42
43pub fn floatFromUnsigned(comptime T: type, comptime MantissaT: type, v: MantissaT) T {
44 return switch (T) {
45 f16 => @bitCast(f16, @truncate(u16, v)),
46 f32 => @bitCast(f32, @truncate(u32, v)),
47 f64 => @bitCast(f64, @truncate(u64, v)),
48 f128 => @bitCast(f128, v),
49 else => unreachable,
50 };
51}
52
53/// Represents a parsed floating point value as its components.
54pub fn Number(comptime T: type) type {
55 return struct {
56 exponent: i64,
57 mantissa: mantissaType(T),
58 negative: bool,
59 /// More than max_mantissa digits were found during parse
60 many_digits: bool,
61 /// The number was a hex-float (e.g. 0x1.234p567)
62 hex: bool,
63 };
64}
65
66/// Determine if 8 bytes are all decimal digits.
67/// This does not care about the order in which the bytes were loaded.
68pub fn isEightDigits(v: u64) bool {
69 const a = v +% 0x4646_4646_4646_4646;
70 const b = v -% 0x3030_3030_3030_3030;
71 return ((a | b) & 0x8080_8080_8080_8080) == 0;
72}
73
74pub fn isDigit(c: u8, comptime base: u8) bool {
75 std.debug.assert(base == 10 or base == 16);
76
77 return if (base == 10)
78 '0' <= c and c <= '9'
79 else
80 '0' <= c and c <= '9' or 'a' <= c and c <= 'f' or 'A' <= c and c <= 'F';
81}
82
83/// Returns the underlying storage type used for the mantissa of floating-point type.
84/// The output unsigned type must have at least as many bits as the input floating-point type.
85pub fn mantissaType(comptime T: type) type {
86 return switch (T) {
87 f16, f32, f64 => u64,
88 f128 => u128,
89 else => unreachable,
90 };
91}
lib/std/fmt/parse_float/convert_eisel_lemire.zig created+843
......@@ -0,0 +1,843 @@
1const std = @import("std");
2const math = std.math;
3const common = @import("common.zig");
4const FloatInfo = @import("FloatInfo.zig");
5const BiasedFp = common.BiasedFp;
6const Number = common.Number;
7
8/// Compute a float using an extended-precision representation.
9///
10/// Fast conversion of a the significant digits and decimal exponent
11/// a float to an extended representation with a binary float. This
12/// algorithm will accurately parse the vast majority of cases,
13/// and uses a 128-bit representation (with a fallback 192-bit
14/// representation).
15///
16/// This algorithm scales the exponent by the decimal exponent
17/// using pre-computed powers-of-5, and calculates if the
18/// representation can be unambiguously rounded to the nearest
19/// machine float. Near-halfway cases are not handled here,
20/// and are represented by a negative, biased binary exponent.
21///
22/// The algorithm is described in detail in "Daniel Lemire, Number Parsing
23/// at a Gigabyte per Second" in section 5, "Fast Algorithm", and
24/// section 6, "Exact Numbers And Ties", available online:
25/// <https://arxiv.org/abs/2101.11408.pdf>.
26pub fn convertEiselLemire(comptime T: type, q: i64, w_: u64) ?BiasedFp(f64) {
27 std.debug.assert(T == f16 or T == f32 or T == f64);
28 var w = w_;
29 const float_info = FloatInfo.from(T);
30
31 // Short-circuit if the value can only be a literal 0 or infinity.
32 if (w == 0 or q < float_info.smallest_power_of_ten) {
33 return BiasedFp(f64).zero();
34 } else if (q > float_info.largest_power_of_ten) {
35 return BiasedFp(f64).inf(T);
36 }
37
38 // Normalize our significant digits, so the most-significant bit is set.
39 const lz = @clz(u64, @bitCast(u64, w));
40 w = math.shl(u64, w, lz);
41
42 const r = computeProductApprox(q, w, float_info.mantissa_explicit_bits + 3);
43 if (r.lo == 0xffff_ffff_ffff_ffff) {
44 // If we have failed to approximate w x 5^-q with our 128-bit value.
45 // Since the addition of 1 could lead to an overflow which could then
46 // round up over the half-way point, this can lead to improper rounding
47 // of a float.
48 //
49 // However, this can only occur if q ∈ [-27, 55]. The upper bound of q
50 // is 55 because 5^55 < 2^128, however, this can only happen if 5^q > 2^64,
51 // since otherwise the product can be represented in 64-bits, producing
52 // an exact result. For negative exponents, rounding-to-even can
53 // only occur if 5^-q < 2^64.
54 //
55 // For detailed explanations of rounding for negative exponents, see
56 // <https://arxiv.org/pdf/2101.11408.pdf#section.9.1>. For detailed
57 // explanations of rounding for positive exponents, see
58 // <https://arxiv.org/pdf/2101.11408.pdf#section.8>.
59 const inside_safe_exponent = q >= -27 and q <= 55;
60 if (!inside_safe_exponent) {
61 return null;
62 }
63 }
64
65 const upper_bit = @intCast(i32, r.hi >> 63);
66 var mantissa = math.shr(u64, r.hi, upper_bit + 64 - @intCast(i32, float_info.mantissa_explicit_bits) - 3);
67 var power2 = power(@intCast(i32, q)) + upper_bit - @intCast(i32, lz) - float_info.minimum_exponent;
68 if (power2 <= 0) {
69 if (-power2 + 1 >= 64) {
70 // Have more than 64 bits below the minimum exponent, must be 0.
71 return BiasedFp(f64).zero();
72 }
73 // Have a subnormal value.
74 mantissa = math.shr(u64, mantissa, -power2 + 1);
75 mantissa += mantissa & 1;
76 mantissa >>= 1;
77 power2 = @boolToInt(mantissa >= (1 << float_info.mantissa_explicit_bits));
78 return BiasedFp(f64){ .f = mantissa, .e = power2 };
79 }
80
81 // Need to handle rounding ties. Normally, we need to round up,
82 // but if we fall right in between and and we have an even basis, we
83 // need to round down.
84 //
85 // This will only occur if:
86 // 1. The lower 64 bits of the 128-bit representation is 0.
87 // IE, 5^q fits in single 64-bit word.
88 // 2. The least-significant bit prior to truncated mantissa is odd.
89 // 3. All the bits truncated when shifting to mantissa bits + 1 are 0.
90 //
91 // Or, we may fall between two floats: we are exactly halfway.
92 if (r.lo <= 1 and
93 q >= float_info.min_exponent_round_to_even and
94 q <= float_info.max_exponent_round_to_even and
95 mantissa & 3 == 1 and
96 math.shl(u64, mantissa, (upper_bit + 64 - @intCast(i32, float_info.mantissa_explicit_bits) - 3)) == r.hi)
97 {
98 // Zero the lowest bit, so we don't round up.
99 mantissa &= ~@as(u64, 1);
100 }
101
102 // Round-to-even, then shift the significant digits into place.
103 mantissa += mantissa & 1;
104 mantissa >>= 1;
105 if (mantissa >= 2 << float_info.mantissa_explicit_bits) {
106 // Rounding up overflowed, so the carry bit is set. Set the
107 // mantissa to 1 (only the implicit, hidden bit is set) and
108 // increase the exponent.
109 mantissa = 1 << float_info.mantissa_explicit_bits;
110 power2 += 1;
111 }
112
113 // Zero out the hidden bit
114 mantissa &= ~(@as(u64, 1) << float_info.mantissa_explicit_bits);
115 if (power2 >= float_info.infinite_power) {
116 // Exponent is above largest normal value, must be infinite
117 return BiasedFp(f64).inf(T);
118 }
119
120 return BiasedFp(f64){ .f = mantissa, .e = power2 };
121}
122
123/// Calculate a base 2 exponent from a decimal exponent.
124/// This uses a pre-computed integer approximation for
125/// log2(10), where 217706 / 2^16 is accurate for the
126/// entire range of non-finite decimal exponents.
127fn power(q: i32) i32 {
128 return ((q *% (152170 + 65536)) >> 16) + 63;
129}
130
131const U128 = struct {
132 lo: u64,
133 hi: u64,
134
135 pub fn new(lo: u64, hi: u64) U128 {
136 return .{ .lo = lo, .hi = hi };
137 }
138
139 pub fn mul(a: u64, b: u64) U128 {
140 const x = @as(u128, a) * b;
141 return .{
142 .hi = @truncate(u64, x >> 64),
143 .lo = @truncate(u64, x),
144 };
145 }
146};
147
148// This will compute or rather approximate w * 5**q and return a pair of 64-bit words
149// approximating the result, with the "high" part corresponding to the most significant
150// bits and the low part corresponding to the least significant bits.
151fn computeProductApprox(q: i64, w: u64, comptime precision: usize) U128 {
152 std.debug.assert(q >= eisel_lemire_smallest_power_of_five);
153 std.debug.assert(q <= eisel_lemire_largest_power_of_five);
154 std.debug.assert(precision <= 64);
155
156 const mask = if (precision < 64)
157 0xffff_ffff_ffff_ffff >> precision
158 else
159 0xffff_ffff_ffff_ffff;
160
161 // 5^q < 2^64, then the multiplication always provides an exact value.
162 // That means whenever we need to round ties to even, we always have
163 // an exact value.
164 const index = @intCast(usize, q - @intCast(i64, eisel_lemire_smallest_power_of_five));
165 const pow5 = eisel_lemire_table_powers_of_five_128[index];
166
167 // Only need one multiplication as long as there is 1 zero but
168 // in the explicit mantissa bits, +1 for the hidden bit, +1 to
169 // determine the rounding direction, +1 for if the computed
170 // product has a leading zero.
171 var first = U128.mul(w, pow5.lo);
172 if (first.hi & mask == mask) {
173 // Need to do a second multiplication to get better precision
174 // for the lower product. This will always be exact
175 // where q is < 55, since 5^55 < 2^128. If this wraps,
176 // then we need to need to round up the hi product.
177 const second = U128.mul(w, pow5.hi);
178
179 first.lo +%= second.hi;
180 if (second.hi > first.lo) {
181 first.hi += 1;
182 }
183 }
184
185 return .{ .lo = first.lo, .hi = first.hi };
186}
187
188// Eisel-Lemire tables ~10Kb
189const eisel_lemire_smallest_power_of_five = -342;
190const eisel_lemire_largest_power_of_five = 308;
191const eisel_lemire_table_powers_of_five_128 = [_]U128{
192 U128.new(0xeef453d6923bd65a, 0x113faa2906a13b3f), // 5^-342
193 U128.new(0x9558b4661b6565f8, 0x4ac7ca59a424c507), // 5^-341
194 U128.new(0xbaaee17fa23ebf76, 0x5d79bcf00d2df649), // 5^-340
195 U128.new(0xe95a99df8ace6f53, 0xf4d82c2c107973dc), // 5^-339
196 U128.new(0x91d8a02bb6c10594, 0x79071b9b8a4be869), // 5^-338
197 U128.new(0xb64ec836a47146f9, 0x9748e2826cdee284), // 5^-337
198 U128.new(0xe3e27a444d8d98b7, 0xfd1b1b2308169b25), // 5^-336
199 U128.new(0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7), // 5^-335
200 U128.new(0xb208ef855c969f4f, 0xbdbd2d335e51a935), // 5^-334
201 U128.new(0xde8b2b66b3bc4723, 0xad2c788035e61382), // 5^-333
202 U128.new(0x8b16fb203055ac76, 0x4c3bcb5021afcc31), // 5^-332
203 U128.new(0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d), // 5^-331
204 U128.new(0xd953e8624b85dd78, 0xd71d6dad34a2af0d), // 5^-330
205 U128.new(0x87d4713d6f33aa6b, 0x8672648c40e5ad68), // 5^-329
206 U128.new(0xa9c98d8ccb009506, 0x680efdaf511f18c2), // 5^-328
207 U128.new(0xd43bf0effdc0ba48, 0x212bd1b2566def2), // 5^-327
208 U128.new(0x84a57695fe98746d, 0x14bb630f7604b57), // 5^-326
209 U128.new(0xa5ced43b7e3e9188, 0x419ea3bd35385e2d), // 5^-325
210 U128.new(0xcf42894a5dce35ea, 0x52064cac828675b9), // 5^-324
211 U128.new(0x818995ce7aa0e1b2, 0x7343efebd1940993), // 5^-323
212 U128.new(0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8), // 5^-322
213 U128.new(0xca66fa129f9b60a6, 0xd41a26e077774ef6), // 5^-321
214 U128.new(0xfd00b897478238d0, 0x8920b098955522b4), // 5^-320
215 U128.new(0x9e20735e8cb16382, 0x55b46e5f5d5535b0), // 5^-319
216 U128.new(0xc5a890362fddbc62, 0xeb2189f734aa831d), // 5^-318
217 U128.new(0xf712b443bbd52b7b, 0xa5e9ec7501d523e4), // 5^-317
218 U128.new(0x9a6bb0aa55653b2d, 0x47b233c92125366e), // 5^-316
219 U128.new(0xc1069cd4eabe89f8, 0x999ec0bb696e840a), // 5^-315
220 U128.new(0xf148440a256e2c76, 0xc00670ea43ca250d), // 5^-314
221 U128.new(0x96cd2a865764dbca, 0x380406926a5e5728), // 5^-313
222 U128.new(0xbc807527ed3e12bc, 0xc605083704f5ecf2), // 5^-312
223 U128.new(0xeba09271e88d976b, 0xf7864a44c633682e), // 5^-311
224 U128.new(0x93445b8731587ea3, 0x7ab3ee6afbe0211d), // 5^-310
225 U128.new(0xb8157268fdae9e4c, 0x5960ea05bad82964), // 5^-309
226 U128.new(0xe61acf033d1a45df, 0x6fb92487298e33bd), // 5^-308
227 U128.new(0x8fd0c16206306bab, 0xa5d3b6d479f8e056), // 5^-307
228 U128.new(0xb3c4f1ba87bc8696, 0x8f48a4899877186c), // 5^-306
229 U128.new(0xe0b62e2929aba83c, 0x331acdabfe94de87), // 5^-305
230 U128.new(0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14), // 5^-304
231 U128.new(0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9), // 5^-303
232 U128.new(0xdb71e91432b1a24a, 0xc9e82cd9f69d6150), // 5^-302
233 U128.new(0x892731ac9faf056e, 0xbe311c083a225cd2), // 5^-301
234 U128.new(0xab70fe17c79ac6ca, 0x6dbd630a48aaf406), // 5^-300
235 U128.new(0xd64d3d9db981787d, 0x92cbbccdad5b108), // 5^-299
236 U128.new(0x85f0468293f0eb4e, 0x25bbf56008c58ea5), // 5^-298
237 U128.new(0xa76c582338ed2621, 0xaf2af2b80af6f24e), // 5^-297
238 U128.new(0xd1476e2c07286faa, 0x1af5af660db4aee1), // 5^-296
239 U128.new(0x82cca4db847945ca, 0x50d98d9fc890ed4d), // 5^-295
240 U128.new(0xa37fce126597973c, 0xe50ff107bab528a0), // 5^-294
241 U128.new(0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8), // 5^-293
242 U128.new(0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a), // 5^-292
243 U128.new(0x9faacf3df73609b1, 0x77b191618c54e9ac), // 5^-291
244 U128.new(0xc795830d75038c1d, 0xd59df5b9ef6a2417), // 5^-290
245 U128.new(0xf97ae3d0d2446f25, 0x4b0573286b44ad1d), // 5^-289
246 U128.new(0x9becce62836ac577, 0x4ee367f9430aec32), // 5^-288
247 U128.new(0xc2e801fb244576d5, 0x229c41f793cda73f), // 5^-287
248 U128.new(0xf3a20279ed56d48a, 0x6b43527578c1110f), // 5^-286
249 U128.new(0x9845418c345644d6, 0x830a13896b78aaa9), // 5^-285
250 U128.new(0xbe5691ef416bd60c, 0x23cc986bc656d553), // 5^-284
251 U128.new(0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8), // 5^-283
252 U128.new(0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9), // 5^-282
253 U128.new(0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53), // 5^-281
254 U128.new(0xe858ad248f5c22c9, 0xd1b3400f8f9cff68), // 5^-280
255 U128.new(0x91376c36d99995be, 0x23100809b9c21fa1), // 5^-279
256 U128.new(0xb58547448ffffb2d, 0xabd40a0c2832a78a), // 5^-278
257 U128.new(0xe2e69915b3fff9f9, 0x16c90c8f323f516c), // 5^-277
258 U128.new(0x8dd01fad907ffc3b, 0xae3da7d97f6792e3), // 5^-276
259 U128.new(0xb1442798f49ffb4a, 0x99cd11cfdf41779c), // 5^-275
260 U128.new(0xdd95317f31c7fa1d, 0x40405643d711d583), // 5^-274
261 U128.new(0x8a7d3eef7f1cfc52, 0x482835ea666b2572), // 5^-273
262 U128.new(0xad1c8eab5ee43b66, 0xda3243650005eecf), // 5^-272
263 U128.new(0xd863b256369d4a40, 0x90bed43e40076a82), // 5^-271
264 U128.new(0x873e4f75e2224e68, 0x5a7744a6e804a291), // 5^-270
265 U128.new(0xa90de3535aaae202, 0x711515d0a205cb36), // 5^-269
266 U128.new(0xd3515c2831559a83, 0xd5a5b44ca873e03), // 5^-268
267 U128.new(0x8412d9991ed58091, 0xe858790afe9486c2), // 5^-267
268 U128.new(0xa5178fff668ae0b6, 0x626e974dbe39a872), // 5^-266
269 U128.new(0xce5d73ff402d98e3, 0xfb0a3d212dc8128f), // 5^-265
270 U128.new(0x80fa687f881c7f8e, 0x7ce66634bc9d0b99), // 5^-264
271 U128.new(0xa139029f6a239f72, 0x1c1fffc1ebc44e80), // 5^-263
272 U128.new(0xc987434744ac874e, 0xa327ffb266b56220), // 5^-262
273 U128.new(0xfbe9141915d7a922, 0x4bf1ff9f0062baa8), // 5^-261
274 U128.new(0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9), // 5^-260
275 U128.new(0xc4ce17b399107c22, 0xcb550fb4384d21d3), // 5^-259
276 U128.new(0xf6019da07f549b2b, 0x7e2a53a146606a48), // 5^-258
277 U128.new(0x99c102844f94e0fb, 0x2eda7444cbfc426d), // 5^-257
278 U128.new(0xc0314325637a1939, 0xfa911155fefb5308), // 5^-256
279 U128.new(0xf03d93eebc589f88, 0x793555ab7eba27ca), // 5^-255
280 U128.new(0x96267c7535b763b5, 0x4bc1558b2f3458de), // 5^-254
281 U128.new(0xbbb01b9283253ca2, 0x9eb1aaedfb016f16), // 5^-253
282 U128.new(0xea9c227723ee8bcb, 0x465e15a979c1cadc), // 5^-252
283 U128.new(0x92a1958a7675175f, 0xbfacd89ec191ec9), // 5^-251
284 U128.new(0xb749faed14125d36, 0xcef980ec671f667b), // 5^-250
285 U128.new(0xe51c79a85916f484, 0x82b7e12780e7401a), // 5^-249
286 U128.new(0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810), // 5^-248
287 U128.new(0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15), // 5^-247
288 U128.new(0xdfbdcece67006ac9, 0x67a791e093e1d49a), // 5^-246
289 U128.new(0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0), // 5^-245
290 U128.new(0xaecc49914078536d, 0x58fae9f773886e18), // 5^-244
291 U128.new(0xda7f5bf590966848, 0xaf39a475506a899e), // 5^-243
292 U128.new(0x888f99797a5e012d, 0x6d8406c952429603), // 5^-242
293 U128.new(0xaab37fd7d8f58178, 0xc8e5087ba6d33b83), // 5^-241
294 U128.new(0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64), // 5^-240
295 U128.new(0x855c3be0a17fcd26, 0x5cf2eea09a55067f), // 5^-239
296 U128.new(0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e), // 5^-238
297 U128.new(0xd0601d8efc57b08b, 0xf13b94daf124da26), // 5^-237
298 U128.new(0x823c12795db6ce57, 0x76c53d08d6b70858), // 5^-236
299 U128.new(0xa2cb1717b52481ed, 0x54768c4b0c64ca6e), // 5^-235
300 U128.new(0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09), // 5^-234
301 U128.new(0xfe5d54150b090b02, 0xd3f93b35435d7c4c), // 5^-233
302 U128.new(0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf), // 5^-232
303 U128.new(0xc6b8e9b0709f109a, 0x359ab6419ca1091b), // 5^-231
304 U128.new(0xf867241c8cc6d4c0, 0xc30163d203c94b62), // 5^-230
305 U128.new(0x9b407691d7fc44f8, 0x79e0de63425dcf1d), // 5^-229
306 U128.new(0xc21094364dfb5636, 0x985915fc12f542e4), // 5^-228
307 U128.new(0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d), // 5^-227
308 U128.new(0x979cf3ca6cec5b5a, 0xa705992ceecf9c42), // 5^-226
309 U128.new(0xbd8430bd08277231, 0x50c6ff782a838353), // 5^-225
310 U128.new(0xece53cec4a314ebd, 0xa4f8bf5635246428), // 5^-224
311 U128.new(0x940f4613ae5ed136, 0x871b7795e136be99), // 5^-223
312 U128.new(0xb913179899f68584, 0x28e2557b59846e3f), // 5^-222
313 U128.new(0xe757dd7ec07426e5, 0x331aeada2fe589cf), // 5^-221
314 U128.new(0x9096ea6f3848984f, 0x3ff0d2c85def7621), // 5^-220
315 U128.new(0xb4bca50b065abe63, 0xfed077a756b53a9), // 5^-219
316 U128.new(0xe1ebce4dc7f16dfb, 0xd3e8495912c62894), // 5^-218
317 U128.new(0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c), // 5^-217
318 U128.new(0xb080392cc4349dec, 0xbd8d794d96aacfb3), // 5^-216
319 U128.new(0xdca04777f541c567, 0xecf0d7a0fc5583a0), // 5^-215
320 U128.new(0x89e42caaf9491b60, 0xf41686c49db57244), // 5^-214
321 U128.new(0xac5d37d5b79b6239, 0x311c2875c522ced5), // 5^-213
322 U128.new(0xd77485cb25823ac7, 0x7d633293366b828b), // 5^-212
323 U128.new(0x86a8d39ef77164bc, 0xae5dff9c02033197), // 5^-211
324 U128.new(0xa8530886b54dbdeb, 0xd9f57f830283fdfc), // 5^-210
325 U128.new(0xd267caa862a12d66, 0xd072df63c324fd7b), // 5^-209
326 U128.new(0x8380dea93da4bc60, 0x4247cb9e59f71e6d), // 5^-208
327 U128.new(0xa46116538d0deb78, 0x52d9be85f074e608), // 5^-207
328 U128.new(0xcd795be870516656, 0x67902e276c921f8b), // 5^-206
329 U128.new(0x806bd9714632dff6, 0xba1cd8a3db53b6), // 5^-205
330 U128.new(0xa086cfcd97bf97f3, 0x80e8a40eccd228a4), // 5^-204
331 U128.new(0xc8a883c0fdaf7df0, 0x6122cd128006b2cd), // 5^-203
332 U128.new(0xfad2a4b13d1b5d6c, 0x796b805720085f81), // 5^-202
333 U128.new(0x9cc3a6eec6311a63, 0xcbe3303674053bb0), // 5^-201
334 U128.new(0xc3f490aa77bd60fc, 0xbedbfc4411068a9c), // 5^-200
335 U128.new(0xf4f1b4d515acb93b, 0xee92fb5515482d44), // 5^-199
336 U128.new(0x991711052d8bf3c5, 0x751bdd152d4d1c4a), // 5^-198
337 U128.new(0xbf5cd54678eef0b6, 0xd262d45a78a0635d), // 5^-197
338 U128.new(0xef340a98172aace4, 0x86fb897116c87c34), // 5^-196
339 U128.new(0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0), // 5^-195
340 U128.new(0xbae0a846d2195712, 0x8974836059cca109), // 5^-194
341 U128.new(0xe998d258869facd7, 0x2bd1a438703fc94b), // 5^-193
342 U128.new(0x91ff83775423cc06, 0x7b6306a34627ddcf), // 5^-192
343 U128.new(0xb67f6455292cbf08, 0x1a3bc84c17b1d542), // 5^-191
344 U128.new(0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93), // 5^-190
345 U128.new(0x8e938662882af53e, 0x547eb47b7282ee9c), // 5^-189
346 U128.new(0xb23867fb2a35b28d, 0xe99e619a4f23aa43), // 5^-188
347 U128.new(0xdec681f9f4c31f31, 0x6405fa00e2ec94d4), // 5^-187
348 U128.new(0x8b3c113c38f9f37e, 0xde83bc408dd3dd04), // 5^-186
349 U128.new(0xae0b158b4738705e, 0x9624ab50b148d445), // 5^-185
350 U128.new(0xd98ddaee19068c76, 0x3badd624dd9b0957), // 5^-184
351 U128.new(0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6), // 5^-183
352 U128.new(0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c), // 5^-182
353 U128.new(0xd47487cc8470652b, 0x7647c3200069671f), // 5^-181
354 U128.new(0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073), // 5^-180
355 U128.new(0xa5fb0a17c777cf09, 0xf468107100525890), // 5^-179
356 U128.new(0xcf79cc9db955c2cc, 0x7182148d4066eeb4), // 5^-178
357 U128.new(0x81ac1fe293d599bf, 0xc6f14cd848405530), // 5^-177
358 U128.new(0xa21727db38cb002f, 0xb8ada00e5a506a7c), // 5^-176
359 U128.new(0xca9cf1d206fdc03b, 0xa6d90811f0e4851c), // 5^-175
360 U128.new(0xfd442e4688bd304a, 0x908f4a166d1da663), // 5^-174
361 U128.new(0x9e4a9cec15763e2e, 0x9a598e4e043287fe), // 5^-173
362 U128.new(0xc5dd44271ad3cdba, 0x40eff1e1853f29fd), // 5^-172
363 U128.new(0xf7549530e188c128, 0xd12bee59e68ef47c), // 5^-171
364 U128.new(0x9a94dd3e8cf578b9, 0x82bb74f8301958ce), // 5^-170
365 U128.new(0xc13a148e3032d6e7, 0xe36a52363c1faf01), // 5^-169
366 U128.new(0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1), // 5^-168
367 U128.new(0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9), // 5^-167
368 U128.new(0xbcb2b812db11a5de, 0x7415d448f6b6f0e7), // 5^-166
369 U128.new(0xebdf661791d60f56, 0x111b495b3464ad21), // 5^-165
370 U128.new(0x936b9fcebb25c995, 0xcab10dd900beec34), // 5^-164
371 U128.new(0xb84687c269ef3bfb, 0x3d5d514f40eea742), // 5^-163
372 U128.new(0xe65829b3046b0afa, 0xcb4a5a3112a5112), // 5^-162
373 U128.new(0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab), // 5^-161
374 U128.new(0xb3f4e093db73a093, 0x59ed216765690f56), // 5^-160
375 U128.new(0xe0f218b8d25088b8, 0x306869c13ec3532c), // 5^-159
376 U128.new(0x8c974f7383725573, 0x1e414218c73a13fb), // 5^-158
377 U128.new(0xafbd2350644eeacf, 0xe5d1929ef90898fa), // 5^-157
378 U128.new(0xdbac6c247d62a583, 0xdf45f746b74abf39), // 5^-156
379 U128.new(0x894bc396ce5da772, 0x6b8bba8c328eb783), // 5^-155
380 U128.new(0xab9eb47c81f5114f, 0x66ea92f3f326564), // 5^-154
381 U128.new(0xd686619ba27255a2, 0xc80a537b0efefebd), // 5^-153
382 U128.new(0x8613fd0145877585, 0xbd06742ce95f5f36), // 5^-152
383 U128.new(0xa798fc4196e952e7, 0x2c48113823b73704), // 5^-151
384 U128.new(0xd17f3b51fca3a7a0, 0xf75a15862ca504c5), // 5^-150
385 U128.new(0x82ef85133de648c4, 0x9a984d73dbe722fb), // 5^-149
386 U128.new(0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba), // 5^-148
387 U128.new(0xcc963fee10b7d1b3, 0x318df905079926a8), // 5^-147
388 U128.new(0xffbbcfe994e5c61f, 0xfdf17746497f7052), // 5^-146
389 U128.new(0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633), // 5^-145
390 U128.new(0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0), // 5^-144
391 U128.new(0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0), // 5^-143
392 U128.new(0x9c1661a651213e2d, 0x6bea10ca65c084e), // 5^-142
393 U128.new(0xc31bfa0fe5698db8, 0x486e494fcff30a62), // 5^-141
394 U128.new(0xf3e2f893dec3f126, 0x5a89dba3c3efccfa), // 5^-140
395 U128.new(0x986ddb5c6b3a76b7, 0xf89629465a75e01c), // 5^-139
396 U128.new(0xbe89523386091465, 0xf6bbb397f1135823), // 5^-138
397 U128.new(0xee2ba6c0678b597f, 0x746aa07ded582e2c), // 5^-137
398 U128.new(0x94db483840b717ef, 0xa8c2a44eb4571cdc), // 5^-136
399 U128.new(0xba121a4650e4ddeb, 0x92f34d62616ce413), // 5^-135
400 U128.new(0xe896a0d7e51e1566, 0x77b020baf9c81d17), // 5^-134
401 U128.new(0x915e2486ef32cd60, 0xace1474dc1d122e), // 5^-133
402 U128.new(0xb5b5ada8aaff80b8, 0xd819992132456ba), // 5^-132
403 U128.new(0xe3231912d5bf60e6, 0x10e1fff697ed6c69), // 5^-131
404 U128.new(0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1), // 5^-130
405 U128.new(0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2), // 5^-129
406 U128.new(0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde), // 5^-128
407 U128.new(0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b), // 5^-127
408 U128.new(0xad4ab7112eb3929d, 0x86c16c98d2c953c6), // 5^-126
409 U128.new(0xd89d64d57a607744, 0xe871c7bf077ba8b7), // 5^-125
410 U128.new(0x87625f056c7c4a8b, 0x11471cd764ad4972), // 5^-124
411 U128.new(0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf), // 5^-123
412 U128.new(0xd389b47879823479, 0x4aff1d108d4ec2c3), // 5^-122
413 U128.new(0x843610cb4bf160cb, 0xcedf722a585139ba), // 5^-121
414 U128.new(0xa54394fe1eedb8fe, 0xc2974eb4ee658828), // 5^-120
415 U128.new(0xce947a3da6a9273e, 0x733d226229feea32), // 5^-119
416 U128.new(0x811ccc668829b887, 0x806357d5a3f525f), // 5^-118
417 U128.new(0xa163ff802a3426a8, 0xca07c2dcb0cf26f7), // 5^-117
418 U128.new(0xc9bcff6034c13052, 0xfc89b393dd02f0b5), // 5^-116
419 U128.new(0xfc2c3f3841f17c67, 0xbbac2078d443ace2), // 5^-115
420 U128.new(0x9d9ba7832936edc0, 0xd54b944b84aa4c0d), // 5^-114
421 U128.new(0xc5029163f384a931, 0xa9e795e65d4df11), // 5^-113
422 U128.new(0xf64335bcf065d37d, 0x4d4617b5ff4a16d5), // 5^-112
423 U128.new(0x99ea0196163fa42e, 0x504bced1bf8e4e45), // 5^-111
424 U128.new(0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6), // 5^-110
425 U128.new(0xf07da27a82c37088, 0x5d767327bb4e5a4c), // 5^-109
426 U128.new(0x964e858c91ba2655, 0x3a6a07f8d510f86f), // 5^-108
427 U128.new(0xbbe226efb628afea, 0x890489f70a55368b), // 5^-107
428 U128.new(0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e), // 5^-106
429 U128.new(0x92c8ae6b464fc96f, 0x3b0b8bc90012929d), // 5^-105
430 U128.new(0xb77ada0617e3bbcb, 0x9ce6ebb40173744), // 5^-104
431 U128.new(0xe55990879ddcaabd, 0xcc420a6a101d0515), // 5^-103
432 U128.new(0x8f57fa54c2a9eab6, 0x9fa946824a12232d), // 5^-102
433 U128.new(0xb32df8e9f3546564, 0x47939822dc96abf9), // 5^-101
434 U128.new(0xdff9772470297ebd, 0x59787e2b93bc56f7), // 5^-100
435 U128.new(0x8bfbea76c619ef36, 0x57eb4edb3c55b65a), // 5^-99
436 U128.new(0xaefae51477a06b03, 0xede622920b6b23f1), // 5^-98
437 U128.new(0xdab99e59958885c4, 0xe95fab368e45eced), // 5^-97
438 U128.new(0x88b402f7fd75539b, 0x11dbcb0218ebb414), // 5^-96
439 U128.new(0xaae103b5fcd2a881, 0xd652bdc29f26a119), // 5^-95
440 U128.new(0xd59944a37c0752a2, 0x4be76d3346f0495f), // 5^-94
441 U128.new(0x857fcae62d8493a5, 0x6f70a4400c562ddb), // 5^-93
442 U128.new(0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952), // 5^-92
443 U128.new(0xd097ad07a71f26b2, 0x7e2000a41346a7a7), // 5^-91
444 U128.new(0x825ecc24c873782f, 0x8ed400668c0c28c8), // 5^-90
445 U128.new(0xa2f67f2dfa90563b, 0x728900802f0f32fa), // 5^-89
446 U128.new(0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9), // 5^-88
447 U128.new(0xfea126b7d78186bc, 0xe2f610c84987bfa8), // 5^-87
448 U128.new(0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9), // 5^-86
449 U128.new(0xc6ede63fa05d3143, 0x91503d1c79720dbb), // 5^-85
450 U128.new(0xf8a95fcf88747d94, 0x75a44c6397ce912a), // 5^-84
451 U128.new(0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba), // 5^-83
452 U128.new(0xc24452da229b021b, 0xfbe85badce996168), // 5^-82
453 U128.new(0xf2d56790ab41c2a2, 0xfae27299423fb9c3), // 5^-81
454 U128.new(0x97c560ba6b0919a5, 0xdccd879fc967d41a), // 5^-80
455 U128.new(0xbdb6b8e905cb600f, 0x5400e987bbc1c920), // 5^-79
456 U128.new(0xed246723473e3813, 0x290123e9aab23b68), // 5^-78
457 U128.new(0x9436c0760c86e30b, 0xf9a0b6720aaf6521), // 5^-77
458 U128.new(0xb94470938fa89bce, 0xf808e40e8d5b3e69), // 5^-76
459 U128.new(0xe7958cb87392c2c2, 0xb60b1d1230b20e04), // 5^-75
460 U128.new(0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2), // 5^-74
461 U128.new(0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3), // 5^-73
462 U128.new(0xe2280b6c20dd5232, 0x25c6da63c38de1b0), // 5^-72
463 U128.new(0x8d590723948a535f, 0x579c487e5a38ad0e), // 5^-71
464 U128.new(0xb0af48ec79ace837, 0x2d835a9df0c6d851), // 5^-70
465 U128.new(0xdcdb1b2798182244, 0xf8e431456cf88e65), // 5^-69
466 U128.new(0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff), // 5^-68
467 U128.new(0xac8b2d36eed2dac5, 0xe272467e3d222f3f), // 5^-67
468 U128.new(0xd7adf884aa879177, 0x5b0ed81dcc6abb0f), // 5^-66
469 U128.new(0x86ccbb52ea94baea, 0x98e947129fc2b4e9), // 5^-65
470 U128.new(0xa87fea27a539e9a5, 0x3f2398d747b36224), // 5^-64
471 U128.new(0xd29fe4b18e88640e, 0x8eec7f0d19a03aad), // 5^-63
472 U128.new(0x83a3eeeef9153e89, 0x1953cf68300424ac), // 5^-62
473 U128.new(0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7), // 5^-61
474 U128.new(0xcdb02555653131b6, 0x3792f412cb06794d), // 5^-60
475 U128.new(0x808e17555f3ebf11, 0xe2bbd88bbee40bd0), // 5^-59
476 U128.new(0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4), // 5^-58
477 U128.new(0xc8de047564d20a8b, 0xf245825a5a445275), // 5^-57
478 U128.new(0xfb158592be068d2e, 0xeed6e2f0f0d56712), // 5^-56
479 U128.new(0x9ced737bb6c4183d, 0x55464dd69685606b), // 5^-55
480 U128.new(0xc428d05aa4751e4c, 0xaa97e14c3c26b886), // 5^-54
481 U128.new(0xf53304714d9265df, 0xd53dd99f4b3066a8), // 5^-53
482 U128.new(0x993fe2c6d07b7fab, 0xe546a8038efe4029), // 5^-52
483 U128.new(0xbf8fdb78849a5f96, 0xde98520472bdd033), // 5^-51
484 U128.new(0xef73d256a5c0f77c, 0x963e66858f6d4440), // 5^-50
485 U128.new(0x95a8637627989aad, 0xdde7001379a44aa8), // 5^-49
486 U128.new(0xbb127c53b17ec159, 0x5560c018580d5d52), // 5^-48
487 U128.new(0xe9d71b689dde71af, 0xaab8f01e6e10b4a6), // 5^-47
488 U128.new(0x9226712162ab070d, 0xcab3961304ca70e8), // 5^-46
489 U128.new(0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22), // 5^-45
490 U128.new(0xe45c10c42a2b3b05, 0x8cb89a7db77c506a), // 5^-44
491 U128.new(0x8eb98a7a9a5b04e3, 0x77f3608e92adb242), // 5^-43
492 U128.new(0xb267ed1940f1c61c, 0x55f038b237591ed3), // 5^-42
493 U128.new(0xdf01e85f912e37a3, 0x6b6c46dec52f6688), // 5^-41
494 U128.new(0x8b61313bbabce2c6, 0x2323ac4b3b3da015), // 5^-40
495 U128.new(0xae397d8aa96c1b77, 0xabec975e0a0d081a), // 5^-39
496 U128.new(0xd9c7dced53c72255, 0x96e7bd358c904a21), // 5^-38
497 U128.new(0x881cea14545c7575, 0x7e50d64177da2e54), // 5^-37
498 U128.new(0xaa242499697392d2, 0xdde50bd1d5d0b9e9), // 5^-36
499 U128.new(0xd4ad2dbfc3d07787, 0x955e4ec64b44e864), // 5^-35
500 U128.new(0x84ec3c97da624ab4, 0xbd5af13bef0b113e), // 5^-34
501 U128.new(0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e), // 5^-33
502 U128.new(0xcfb11ead453994ba, 0x67de18eda5814af2), // 5^-32
503 U128.new(0x81ceb32c4b43fcf4, 0x80eacf948770ced7), // 5^-31
504 U128.new(0xa2425ff75e14fc31, 0xa1258379a94d028d), // 5^-30
505 U128.new(0xcad2f7f5359a3b3e, 0x96ee45813a04330), // 5^-29
506 U128.new(0xfd87b5f28300ca0d, 0x8bca9d6e188853fc), // 5^-28
507 U128.new(0x9e74d1b791e07e48, 0x775ea264cf55347e), // 5^-27
508 U128.new(0xc612062576589dda, 0x95364afe032a819e), // 5^-26
509 U128.new(0xf79687aed3eec551, 0x3a83ddbd83f52205), // 5^-25
510 U128.new(0x9abe14cd44753b52, 0xc4926a9672793543), // 5^-24
511 U128.new(0xc16d9a0095928a27, 0x75b7053c0f178294), // 5^-23
512 U128.new(0xf1c90080baf72cb1, 0x5324c68b12dd6339), // 5^-22
513 U128.new(0x971da05074da7bee, 0xd3f6fc16ebca5e04), // 5^-21
514 U128.new(0xbce5086492111aea, 0x88f4bb1ca6bcf585), // 5^-20
515 U128.new(0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6), // 5^-19
516 U128.new(0x9392ee8e921d5d07, 0x3aff322e62439fd0), // 5^-18
517 U128.new(0xb877aa3236a4b449, 0x9befeb9fad487c3), // 5^-17
518 U128.new(0xe69594bec44de15b, 0x4c2ebe687989a9b4), // 5^-16
519 U128.new(0x901d7cf73ab0acd9, 0xf9d37014bf60a11), // 5^-15
520 U128.new(0xb424dc35095cd80f, 0x538484c19ef38c95), // 5^-14
521 U128.new(0xe12e13424bb40e13, 0x2865a5f206b06fba), // 5^-13
522 U128.new(0x8cbccc096f5088cb, 0xf93f87b7442e45d4), // 5^-12
523 U128.new(0xafebff0bcb24aafe, 0xf78f69a51539d749), // 5^-11
524 U128.new(0xdbe6fecebdedd5be, 0xb573440e5a884d1c), // 5^-10
525 U128.new(0x89705f4136b4a597, 0x31680a88f8953031), // 5^-9
526 U128.new(0xabcc77118461cefc, 0xfdc20d2b36ba7c3e), // 5^-8
527 U128.new(0xd6bf94d5e57a42bc, 0x3d32907604691b4d), // 5^-7
528 U128.new(0x8637bd05af6c69b5, 0xa63f9a49c2c1b110), // 5^-6
529 U128.new(0xa7c5ac471b478423, 0xfcf80dc33721d54), // 5^-5
530 U128.new(0xd1b71758e219652b, 0xd3c36113404ea4a9), // 5^-4
531 U128.new(0x83126e978d4fdf3b, 0x645a1cac083126ea), // 5^-3
532 U128.new(0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4), // 5^-2
533 U128.new(0xcccccccccccccccc, 0xcccccccccccccccd), // 5^-1
534 U128.new(0x8000000000000000, 0x0), // 5^0
535 U128.new(0xa000000000000000, 0x0), // 5^1
536 U128.new(0xc800000000000000, 0x0), // 5^2
537 U128.new(0xfa00000000000000, 0x0), // 5^3
538 U128.new(0x9c40000000000000, 0x0), // 5^4
539 U128.new(0xc350000000000000, 0x0), // 5^5
540 U128.new(0xf424000000000000, 0x0), // 5^6
541 U128.new(0x9896800000000000, 0x0), // 5^7
542 U128.new(0xbebc200000000000, 0x0), // 5^8
543 U128.new(0xee6b280000000000, 0x0), // 5^9
544 U128.new(0x9502f90000000000, 0x0), // 5^10
545 U128.new(0xba43b74000000000, 0x0), // 5^11
546 U128.new(0xe8d4a51000000000, 0x0), // 5^12
547 U128.new(0x9184e72a00000000, 0x0), // 5^13
548 U128.new(0xb5e620f480000000, 0x0), // 5^14
549 U128.new(0xe35fa931a0000000, 0x0), // 5^15
550 U128.new(0x8e1bc9bf04000000, 0x0), // 5^16
551 U128.new(0xb1a2bc2ec5000000, 0x0), // 5^17
552 U128.new(0xde0b6b3a76400000, 0x0), // 5^18
553 U128.new(0x8ac7230489e80000, 0x0), // 5^19
554 U128.new(0xad78ebc5ac620000, 0x0), // 5^20
555 U128.new(0xd8d726b7177a8000, 0x0), // 5^21
556 U128.new(0x878678326eac9000, 0x0), // 5^22
557 U128.new(0xa968163f0a57b400, 0x0), // 5^23
558 U128.new(0xd3c21bcecceda100, 0x0), // 5^24
559 U128.new(0x84595161401484a0, 0x0), // 5^25
560 U128.new(0xa56fa5b99019a5c8, 0x0), // 5^26
561 U128.new(0xcecb8f27f4200f3a, 0x0), // 5^27
562 U128.new(0x813f3978f8940984, 0x4000000000000000), // 5^28
563 U128.new(0xa18f07d736b90be5, 0x5000000000000000), // 5^29
564 U128.new(0xc9f2c9cd04674ede, 0xa400000000000000), // 5^30
565 U128.new(0xfc6f7c4045812296, 0x4d00000000000000), // 5^31
566 U128.new(0x9dc5ada82b70b59d, 0xf020000000000000), // 5^32
567 U128.new(0xc5371912364ce305, 0x6c28000000000000), // 5^33
568 U128.new(0xf684df56c3e01bc6, 0xc732000000000000), // 5^34
569 U128.new(0x9a130b963a6c115c, 0x3c7f400000000000), // 5^35
570 U128.new(0xc097ce7bc90715b3, 0x4b9f100000000000), // 5^36
571 U128.new(0xf0bdc21abb48db20, 0x1e86d40000000000), // 5^37
572 U128.new(0x96769950b50d88f4, 0x1314448000000000), // 5^38
573 U128.new(0xbc143fa4e250eb31, 0x17d955a000000000), // 5^39
574 U128.new(0xeb194f8e1ae525fd, 0x5dcfab0800000000), // 5^40
575 U128.new(0x92efd1b8d0cf37be, 0x5aa1cae500000000), // 5^41
576 U128.new(0xb7abc627050305ad, 0xf14a3d9e40000000), // 5^42
577 U128.new(0xe596b7b0c643c719, 0x6d9ccd05d0000000), // 5^43
578 U128.new(0x8f7e32ce7bea5c6f, 0xe4820023a2000000), // 5^44
579 U128.new(0xb35dbf821ae4f38b, 0xdda2802c8a800000), // 5^45
580 U128.new(0xe0352f62a19e306e, 0xd50b2037ad200000), // 5^46
581 U128.new(0x8c213d9da502de45, 0x4526f422cc340000), // 5^47
582 U128.new(0xaf298d050e4395d6, 0x9670b12b7f410000), // 5^48
583 U128.new(0xdaf3f04651d47b4c, 0x3c0cdd765f114000), // 5^49
584 U128.new(0x88d8762bf324cd0f, 0xa5880a69fb6ac800), // 5^50
585 U128.new(0xab0e93b6efee0053, 0x8eea0d047a457a00), // 5^51
586 U128.new(0xd5d238a4abe98068, 0x72a4904598d6d880), // 5^52
587 U128.new(0x85a36366eb71f041, 0x47a6da2b7f864750), // 5^53
588 U128.new(0xa70c3c40a64e6c51, 0x999090b65f67d924), // 5^54
589 U128.new(0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d), // 5^55
590 U128.new(0x82818f1281ed449f, 0xbff8f10e7a8921a4), // 5^56
591 U128.new(0xa321f2d7226895c7, 0xaff72d52192b6a0d), // 5^57
592 U128.new(0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490), // 5^58
593 U128.new(0xfee50b7025c36a08, 0x2f236d04753d5b4), // 5^59
594 U128.new(0x9f4f2726179a2245, 0x1d762422c946590), // 5^60
595 U128.new(0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5), // 5^61
596 U128.new(0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2), // 5^62
597 U128.new(0x9b934c3b330c8577, 0x63cc55f49f88eb2f), // 5^63
598 U128.new(0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb), // 5^64
599 U128.new(0xf316271c7fc3908a, 0x8bef464e3945ef7a), // 5^65
600 U128.new(0x97edd871cfda3a56, 0x97758bf0e3cbb5ac), // 5^66
601 U128.new(0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317), // 5^67
602 U128.new(0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd), // 5^68
603 U128.new(0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a), // 5^69
604 U128.new(0xb975d6b6ee39e436, 0xb3e2fd538e122b44), // 5^70
605 U128.new(0xe7d34c64a9c85d44, 0x60dbbca87196b616), // 5^71
606 U128.new(0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd), // 5^72
607 U128.new(0xb51d13aea4a488dd, 0x6babab6398bdbe41), // 5^73
608 U128.new(0xe264589a4dcdab14, 0xc696963c7eed2dd1), // 5^74
609 U128.new(0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2), // 5^75
610 U128.new(0xb0de65388cc8ada8, 0x3b25a55f43294bcb), // 5^76
611 U128.new(0xdd15fe86affad912, 0x49ef0eb713f39ebe), // 5^77
612 U128.new(0x8a2dbf142dfcc7ab, 0x6e3569326c784337), // 5^78
613 U128.new(0xacb92ed9397bf996, 0x49c2c37f07965404), // 5^79
614 U128.new(0xd7e77a8f87daf7fb, 0xdc33745ec97be906), // 5^80
615 U128.new(0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3), // 5^81
616 U128.new(0xa8acd7c0222311bc, 0xc40832ea0d68ce0c), // 5^82
617 U128.new(0xd2d80db02aabd62b, 0xf50a3fa490c30190), // 5^83
618 U128.new(0x83c7088e1aab65db, 0x792667c6da79e0fa), // 5^84
619 U128.new(0xa4b8cab1a1563f52, 0x577001b891185938), // 5^85
620 U128.new(0xcde6fd5e09abcf26, 0xed4c0226b55e6f86), // 5^86
621 U128.new(0x80b05e5ac60b6178, 0x544f8158315b05b4), // 5^87
622 U128.new(0xa0dc75f1778e39d6, 0x696361ae3db1c721), // 5^88
623 U128.new(0xc913936dd571c84c, 0x3bc3a19cd1e38e9), // 5^89
624 U128.new(0xfb5878494ace3a5f, 0x4ab48a04065c723), // 5^90
625 U128.new(0x9d174b2dcec0e47b, 0x62eb0d64283f9c76), // 5^91
626 U128.new(0xc45d1df942711d9a, 0x3ba5d0bd324f8394), // 5^92
627 U128.new(0xf5746577930d6500, 0xca8f44ec7ee36479), // 5^93
628 U128.new(0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb), // 5^94
629 U128.new(0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e), // 5^95
630 U128.new(0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e), // 5^96
631 U128.new(0x95d04aee3b80ece5, 0xbba1f1d158724a12), // 5^97
632 U128.new(0xbb445da9ca61281f, 0x2a8a6e45ae8edc97), // 5^98
633 U128.new(0xea1575143cf97226, 0xf52d09d71a3293bd), // 5^99
634 U128.new(0x924d692ca61be758, 0x593c2626705f9c56), // 5^100
635 U128.new(0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c), // 5^101
636 U128.new(0xe498f455c38b997a, 0xb6dfb9c0f956447), // 5^102
637 U128.new(0x8edf98b59a373fec, 0x4724bd4189bd5eac), // 5^103
638 U128.new(0xb2977ee300c50fe7, 0x58edec91ec2cb657), // 5^104
639 U128.new(0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed), // 5^105
640 U128.new(0x8b865b215899f46c, 0xbd79e0d20082ee74), // 5^106
641 U128.new(0xae67f1e9aec07187, 0xecd8590680a3aa11), // 5^107
642 U128.new(0xda01ee641a708de9, 0xe80e6f4820cc9495), // 5^108
643 U128.new(0x884134fe908658b2, 0x3109058d147fdcdd), // 5^109
644 U128.new(0xaa51823e34a7eede, 0xbd4b46f0599fd415), // 5^110
645 U128.new(0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a), // 5^111
646 U128.new(0x850fadc09923329e, 0x3e2cf6bc604ddb0), // 5^112
647 U128.new(0xa6539930bf6bff45, 0x84db8346b786151c), // 5^113
648 U128.new(0xcfe87f7cef46ff16, 0xe612641865679a63), // 5^114
649 U128.new(0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e), // 5^115
650 U128.new(0xa26da3999aef7749, 0xe3be5e330f38f09d), // 5^116
651 U128.new(0xcb090c8001ab551c, 0x5cadf5bfd3072cc5), // 5^117
652 U128.new(0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6), // 5^118
653 U128.new(0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa), // 5^119
654 U128.new(0xc646d63501a1511d, 0xb281e1fd541501b8), // 5^120
655 U128.new(0xf7d88bc24209a565, 0x1f225a7ca91a4226), // 5^121
656 U128.new(0x9ae757596946075f, 0x3375788de9b06958), // 5^122
657 U128.new(0xc1a12d2fc3978937, 0x52d6b1641c83ae), // 5^123
658 U128.new(0xf209787bb47d6b84, 0xc0678c5dbd23a49a), // 5^124
659 U128.new(0x9745eb4d50ce6332, 0xf840b7ba963646e0), // 5^125
660 U128.new(0xbd176620a501fbff, 0xb650e5a93bc3d898), // 5^126
661 U128.new(0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe), // 5^127
662 U128.new(0x93ba47c980e98cdf, 0xc66f336c36b10137), // 5^128
663 U128.new(0xb8a8d9bbe123f017, 0xb80b0047445d4184), // 5^129
664 U128.new(0xe6d3102ad96cec1d, 0xa60dc059157491e5), // 5^130
665 U128.new(0x9043ea1ac7e41392, 0x87c89837ad68db2f), // 5^131
666 U128.new(0xb454e4a179dd1877, 0x29babe4598c311fb), // 5^132
667 U128.new(0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a), // 5^133
668 U128.new(0x8ce2529e2734bb1d, 0x1899e4a65f58660c), // 5^134
669 U128.new(0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f), // 5^135
670 U128.new(0xdc21a1171d42645d, 0x76707543f4fa1f73), // 5^136
671 U128.new(0x899504ae72497eba, 0x6a06494a791c53a8), // 5^137
672 U128.new(0xabfa45da0edbde69, 0x487db9d17636892), // 5^138
673 U128.new(0xd6f8d7509292d603, 0x45a9d2845d3c42b6), // 5^139
674 U128.new(0x865b86925b9bc5c2, 0xb8a2392ba45a9b2), // 5^140
675 U128.new(0xa7f26836f282b732, 0x8e6cac7768d7141e), // 5^141
676 U128.new(0xd1ef0244af2364ff, 0x3207d795430cd926), // 5^142
677 U128.new(0x8335616aed761f1f, 0x7f44e6bd49e807b8), // 5^143
678 U128.new(0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6), // 5^144
679 U128.new(0xcd036837130890a1, 0x36dba887c37a8c0f), // 5^145
680 U128.new(0x802221226be55a64, 0xc2494954da2c9789), // 5^146
681 U128.new(0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c), // 5^147
682 U128.new(0xc83553c5c8965d3d, 0x6f92829494e5acc7), // 5^148
683 U128.new(0xfa42a8b73abbf48c, 0xcb772339ba1f17f9), // 5^149
684 U128.new(0x9c69a97284b578d7, 0xff2a760414536efb), // 5^150
685 U128.new(0xc38413cf25e2d70d, 0xfef5138519684aba), // 5^151
686 U128.new(0xf46518c2ef5b8cd1, 0x7eb258665fc25d69), // 5^152
687 U128.new(0x98bf2f79d5993802, 0xef2f773ffbd97a61), // 5^153
688 U128.new(0xbeeefb584aff8603, 0xaafb550ffacfd8fa), // 5^154
689 U128.new(0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38), // 5^155
690 U128.new(0x952ab45cfa97a0b2, 0xdd945a747bf26183), // 5^156
691 U128.new(0xba756174393d88df, 0x94f971119aeef9e4), // 5^157
692 U128.new(0xe912b9d1478ceb17, 0x7a37cd5601aab85d), // 5^158
693 U128.new(0x91abb422ccb812ee, 0xac62e055c10ab33a), // 5^159
694 U128.new(0xb616a12b7fe617aa, 0x577b986b314d6009), // 5^160
695 U128.new(0xe39c49765fdf9d94, 0xed5a7e85fda0b80b), // 5^161
696 U128.new(0x8e41ade9fbebc27d, 0x14588f13be847307), // 5^162
697 U128.new(0xb1d219647ae6b31c, 0x596eb2d8ae258fc8), // 5^163
698 U128.new(0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb), // 5^164
699 U128.new(0x8aec23d680043bee, 0x25de7bb9480d5854), // 5^165
700 U128.new(0xada72ccc20054ae9, 0xaf561aa79a10ae6a), // 5^166
701 U128.new(0xd910f7ff28069da4, 0x1b2ba1518094da04), // 5^167
702 U128.new(0x87aa9aff79042286, 0x90fb44d2f05d0842), // 5^168
703 U128.new(0xa99541bf57452b28, 0x353a1607ac744a53), // 5^169
704 U128.new(0xd3fa922f2d1675f2, 0x42889b8997915ce8), // 5^170
705 U128.new(0x847c9b5d7c2e09b7, 0x69956135febada11), // 5^171
706 U128.new(0xa59bc234db398c25, 0x43fab9837e699095), // 5^172
707 U128.new(0xcf02b2c21207ef2e, 0x94f967e45e03f4bb), // 5^173
708 U128.new(0x8161afb94b44f57d, 0x1d1be0eebac278f5), // 5^174
709 U128.new(0xa1ba1ba79e1632dc, 0x6462d92a69731732), // 5^175
710 U128.new(0xca28a291859bbf93, 0x7d7b8f7503cfdcfe), // 5^176
711 U128.new(0xfcb2cb35e702af78, 0x5cda735244c3d43e), // 5^177
712 U128.new(0x9defbf01b061adab, 0x3a0888136afa64a7), // 5^178
713 U128.new(0xc56baec21c7a1916, 0x88aaa1845b8fdd0), // 5^179
714 U128.new(0xf6c69a72a3989f5b, 0x8aad549e57273d45), // 5^180
715 U128.new(0x9a3c2087a63f6399, 0x36ac54e2f678864b), // 5^181
716 U128.new(0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd), // 5^182
717 U128.new(0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5), // 5^183
718 U128.new(0x969eb7c47859e743, 0x9f644ae5a4b1b325), // 5^184
719 U128.new(0xbc4665b596706114, 0x873d5d9f0dde1fee), // 5^185
720 U128.new(0xeb57ff22fc0c7959, 0xa90cb506d155a7ea), // 5^186
721 U128.new(0x9316ff75dd87cbd8, 0x9a7f12442d588f2), // 5^187
722 U128.new(0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f), // 5^188
723 U128.new(0xe5d3ef282a242e81, 0x8f1668c8a86da5fa), // 5^189
724 U128.new(0x8fa475791a569d10, 0xf96e017d694487bc), // 5^190
725 U128.new(0xb38d92d760ec4455, 0x37c981dcc395a9ac), // 5^191
726 U128.new(0xe070f78d3927556a, 0x85bbe253f47b1417), // 5^192
727 U128.new(0x8c469ab843b89562, 0x93956d7478ccec8e), // 5^193
728 U128.new(0xaf58416654a6babb, 0x387ac8d1970027b2), // 5^194
729 U128.new(0xdb2e51bfe9d0696a, 0x6997b05fcc0319e), // 5^195
730 U128.new(0x88fcf317f22241e2, 0x441fece3bdf81f03), // 5^196
731 U128.new(0xab3c2fddeeaad25a, 0xd527e81cad7626c3), // 5^197
732 U128.new(0xd60b3bd56a5586f1, 0x8a71e223d8d3b074), // 5^198
733 U128.new(0x85c7056562757456, 0xf6872d5667844e49), // 5^199
734 U128.new(0xa738c6bebb12d16c, 0xb428f8ac016561db), // 5^200
735 U128.new(0xd106f86e69d785c7, 0xe13336d701beba52), // 5^201
736 U128.new(0x82a45b450226b39c, 0xecc0024661173473), // 5^202
737 U128.new(0xa34d721642b06084, 0x27f002d7f95d0190), // 5^203
738 U128.new(0xcc20ce9bd35c78a5, 0x31ec038df7b441f4), // 5^204
739 U128.new(0xff290242c83396ce, 0x7e67047175a15271), // 5^205
740 U128.new(0x9f79a169bd203e41, 0xf0062c6e984d386), // 5^206
741 U128.new(0xc75809c42c684dd1, 0x52c07b78a3e60868), // 5^207
742 U128.new(0xf92e0c3537826145, 0xa7709a56ccdf8a82), // 5^208
743 U128.new(0x9bbcc7a142b17ccb, 0x88a66076400bb691), // 5^209
744 U128.new(0xc2abf989935ddbfe, 0x6acff893d00ea435), // 5^210
745 U128.new(0xf356f7ebf83552fe, 0x583f6b8c4124d43), // 5^211
746 U128.new(0x98165af37b2153de, 0xc3727a337a8b704a), // 5^212
747 U128.new(0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c), // 5^213
748 U128.new(0xeda2ee1c7064130c, 0x1162def06f79df73), // 5^214
749 U128.new(0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8), // 5^215
750 U128.new(0xb9a74a0637ce2ee1, 0x6d953e2bd7173692), // 5^216
751 U128.new(0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437), // 5^217
752 U128.new(0x910ab1d4db9914a0, 0x1d9c9892400a22a2), // 5^218
753 U128.new(0xb54d5e4a127f59c8, 0x2503beb6d00cab4b), // 5^219
754 U128.new(0xe2a0b5dc971f303a, 0x2e44ae64840fd61d), // 5^220
755 U128.new(0x8da471a9de737e24, 0x5ceaecfed289e5d2), // 5^221
756 U128.new(0xb10d8e1456105dad, 0x7425a83e872c5f47), // 5^222
757 U128.new(0xdd50f1996b947518, 0xd12f124e28f77719), // 5^223
758 U128.new(0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f), // 5^224
759 U128.new(0xace73cbfdc0bfb7b, 0x636cc64d1001550b), // 5^225
760 U128.new(0xd8210befd30efa5a, 0x3c47f7e05401aa4e), // 5^226
761 U128.new(0x8714a775e3e95c78, 0x65acfaec34810a71), // 5^227
762 U128.new(0xa8d9d1535ce3b396, 0x7f1839a741a14d0d), // 5^228
763 U128.new(0xd31045a8341ca07c, 0x1ede48111209a050), // 5^229
764 U128.new(0x83ea2b892091e44d, 0x934aed0aab460432), // 5^230
765 U128.new(0xa4e4b66b68b65d60, 0xf81da84d5617853f), // 5^231
766 U128.new(0xce1de40642e3f4b9, 0x36251260ab9d668e), // 5^232
767 U128.new(0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019), // 5^233
768 U128.new(0xa1075a24e4421730, 0xb24cf65b8612f81f), // 5^234
769 U128.new(0xc94930ae1d529cfc, 0xdee033f26797b627), // 5^235
770 U128.new(0xfb9b7cd9a4a7443c, 0x169840ef017da3b1), // 5^236
771 U128.new(0x9d412e0806e88aa5, 0x8e1f289560ee864e), // 5^237
772 U128.new(0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2), // 5^238
773 U128.new(0xf5b5d7ec8acb58a2, 0xae10af696774b1db), // 5^239
774 U128.new(0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29), // 5^240
775 U128.new(0xbff610b0cc6edd3f, 0x17fd090a58d32af3), // 5^241
776 U128.new(0xeff394dcff8a948e, 0xddfc4b4cef07f5b0), // 5^242
777 U128.new(0x95f83d0a1fb69cd9, 0x4abdaf101564f98e), // 5^243
778 U128.new(0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1), // 5^244
779 U128.new(0xea53df5fd18d5513, 0x84c86189216dc5ed), // 5^245
780 U128.new(0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4), // 5^246
781 U128.new(0xb7118682dbb66a77, 0x3fbc8c33221dc2a1), // 5^247
782 U128.new(0xe4d5e82392a40515, 0xfabaf3feaa5334a), // 5^248
783 U128.new(0x8f05b1163ba6832d, 0x29cb4d87f2a7400e), // 5^249
784 U128.new(0xb2c71d5bca9023f8, 0x743e20e9ef511012), // 5^250
785 U128.new(0xdf78e4b2bd342cf6, 0x914da9246b255416), // 5^251
786 U128.new(0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e), // 5^252
787 U128.new(0xae9672aba3d0c320, 0xa184ac2473b529b1), // 5^253
788 U128.new(0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e), // 5^254
789 U128.new(0x8865899617fb1871, 0x7e2fa67c7a658892), // 5^255
790 U128.new(0xaa7eebfb9df9de8d, 0xddbb901b98feeab7), // 5^256
791 U128.new(0xd51ea6fa85785631, 0x552a74227f3ea565), // 5^257
792 U128.new(0x8533285c936b35de, 0xd53a88958f87275f), // 5^258
793 U128.new(0xa67ff273b8460356, 0x8a892abaf368f137), // 5^259
794 U128.new(0xd01fef10a657842c, 0x2d2b7569b0432d85), // 5^260
795 U128.new(0x8213f56a67f6b29b, 0x9c3b29620e29fc73), // 5^261
796 U128.new(0xa298f2c501f45f42, 0x8349f3ba91b47b8f), // 5^262
797 U128.new(0xcb3f2f7642717713, 0x241c70a936219a73), // 5^263
798 U128.new(0xfe0efb53d30dd4d7, 0xed238cd383aa0110), // 5^264
799 U128.new(0x9ec95d1463e8a506, 0xf4363804324a40aa), // 5^265
800 U128.new(0xc67bb4597ce2ce48, 0xb143c6053edcd0d5), // 5^266
801 U128.new(0xf81aa16fdc1b81da, 0xdd94b7868e94050a), // 5^267
802 U128.new(0x9b10a4e5e9913128, 0xca7cf2b4191c8326), // 5^268
803 U128.new(0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0), // 5^269
804 U128.new(0xf24a01a73cf2dccf, 0xbc633b39673c8cec), // 5^270
805 U128.new(0x976e41088617ca01, 0xd5be0503e085d813), // 5^271
806 U128.new(0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18), // 5^272
807 U128.new(0xec9c459d51852ba2, 0xddf8e7d60ed1219e), // 5^273
808 U128.new(0x93e1ab8252f33b45, 0xcabb90e5c942b503), // 5^274
809 U128.new(0xb8da1662e7b00a17, 0x3d6a751f3b936243), // 5^275
810 U128.new(0xe7109bfba19c0c9d, 0xcc512670a783ad4), // 5^276
811 U128.new(0x906a617d450187e2, 0x27fb2b80668b24c5), // 5^277
812 U128.new(0xb484f9dc9641e9da, 0xb1f9f660802dedf6), // 5^278
813 U128.new(0xe1a63853bbd26451, 0x5e7873f8a0396973), // 5^279
814 U128.new(0x8d07e33455637eb2, 0xdb0b487b6423e1e8), // 5^280
815 U128.new(0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62), // 5^281
816 U128.new(0xdc5c5301c56b75f7, 0x7641a140cc7810fb), // 5^282
817 U128.new(0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d), // 5^283
818 U128.new(0xac2820d9623bf429, 0x546345fa9fbdcd44), // 5^284
819 U128.new(0xd732290fbacaf133, 0xa97c177947ad4095), // 5^285
820 U128.new(0x867f59a9d4bed6c0, 0x49ed8eabcccc485d), // 5^286
821 U128.new(0xa81f301449ee8c70, 0x5c68f256bfff5a74), // 5^287
822 U128.new(0xd226fc195c6a2f8c, 0x73832eec6fff3111), // 5^288
823 U128.new(0x83585d8fd9c25db7, 0xc831fd53c5ff7eab), // 5^289
824 U128.new(0xa42e74f3d032f525, 0xba3e7ca8b77f5e55), // 5^290
825 U128.new(0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb), // 5^291
826 U128.new(0x80444b5e7aa7cf85, 0x7980d163cf5b81b3), // 5^292
827 U128.new(0xa0555e361951c366, 0xd7e105bcc332621f), // 5^293
828 U128.new(0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7), // 5^294
829 U128.new(0xfa856334878fc150, 0xb14f98f6f0feb951), // 5^295
830 U128.new(0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3), // 5^296
831 U128.new(0xc3b8358109e84f07, 0xa862f80ec4700c8), // 5^297
832 U128.new(0xf4a642e14c6262c8, 0xcd27bb612758c0fa), // 5^298
833 U128.new(0x98e7e9cccfbd7dbd, 0x8038d51cb897789c), // 5^299
834 U128.new(0xbf21e44003acdd2c, 0xe0470a63e6bd56c3), // 5^300
835 U128.new(0xeeea5d5004981478, 0x1858ccfce06cac74), // 5^301
836 U128.new(0x95527a5202df0ccb, 0xf37801e0c43ebc8), // 5^302
837 U128.new(0xbaa718e68396cffd, 0xd30560258f54e6ba), // 5^303
838 U128.new(0xe950df20247c83fd, 0x47c6b82ef32a2069), // 5^304
839 U128.new(0x91d28b7416cdd27e, 0x4cdc331d57fa5441), // 5^305
840 U128.new(0xb6472e511c81471d, 0xe0133fe4adf8e952), // 5^306
841 U128.new(0xe3d8f9e563a198e5, 0x58180fddd97723a6), // 5^307
842 U128.new(0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648), // 5^308
843};
lib/std/fmt/parse_float/convert_fast.zig created+130
......@@ -0,0 +1,130 @@
1//! Representation of a float as the signficant digits and exponent.
2//! The fast path algorithm using machine-sized integers and floats.
3//!
4//! This only works if both the mantissa and the exponent can be exactly
5//! represented as a machine float, since IEE-754 guarantees no rounding
6//! will occur.
7//!
8//! There is an exception: disguised fast-path cases, where we can shift
9//! powers-of-10 from the exponent to the significant digits.
10
11const std = @import("std");
12const math = std.math;
13const common = @import("common.zig");
14const FloatInfo = @import("FloatInfo.zig");
15const Number = common.Number;
16const floatFromU64 = common.floatFromU64;
17
18fn isFastPath(comptime T: type, n: Number(T)) bool {
19 const info = FloatInfo.from(T);
20
21 return info.min_exponent_fast_path <= n.exponent and
22 n.exponent <= info.max_exponent_fast_path_disguised and
23 n.mantissa <= info.max_mantissa_fast_path and
24 !n.many_digits;
25}
26
27// upper bound for tables is floor(mantissaDigits(T) / log2(5))
28// for f64 this is floor(53 / log2(5)) = 22.
29//
30// Must have max_disguised_fast_path - max_exponent_fast_path entries. (82 - 48 = 34 for f128)
31fn fastPow10(comptime T: type, i: usize) T {
32 return switch (T) {
33 f16 => ([8]f16{
34 1e0, 1e1, 1e2, 1e3, 1e4, 0, 0, 0,
35 })[i & 7],
36
37 f32 => ([16]f32{
38 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
39 1e8, 1e9, 1e10, 0, 0, 0, 0, 0,
40 })[i & 15],
41
42 f64 => ([32]f64{
43 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
44 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
45 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0,
46 0, 0, 0, 0, 0, 0, 0, 0,
47 })[i & 31],
48
49 f128 => ([64]f128{
50 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
51 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
52 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23,
53 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31,
54 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
55 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47,
56 1e48, 0, 0, 0, 0, 0, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0,
58 })[i & 63],
59
60 else => unreachable,
61 };
62}
63
64fn fastIntPow10(comptime T: type, i: usize) T {
65 return switch (T) {
66 u64 => ([16]u64{
67 1, 10, 100, 1000,
68 10000, 100000, 1000000, 10000000,
69 100000000, 1000000000, 10000000000, 100000000000,
70 1000000000000, 10000000000000, 100000000000000, 1000000000000000,
71 })[i],
72
73 u128 => ([35]u128{
74 1, 10,
75 100, 1000,
76 10000, 100000,
77 1000000, 10000000,
78 100000000, 1000000000,
79 10000000000, 100000000000,
80 1000000000000, 10000000000000,
81 100000000000000, 1000000000000000,
82 10000000000000000, 100000000000000000,
83 1000000000000000000, 10000000000000000000,
84 100000000000000000000, 1000000000000000000000,
85 10000000000000000000000, 100000000000000000000000,
86 1000000000000000000000000, 10000000000000000000000000,
87 100000000000000000000000000, 1000000000000000000000000000,
88 10000000000000000000000000000, 100000000000000000000000000000,
89 1000000000000000000000000000000, 10000000000000000000000000000000,
90 100000000000000000000000000000000, 1000000000000000000000000000000000,
91 10000000000000000000000000000000000,
92 })[i],
93
94 else => unreachable,
95 };
96}
97
98pub fn convertFast(comptime T: type, n: Number(T)) ?T {
99 const MantissaT = common.mantissaType(T);
100
101 if (!isFastPath(T, n)) {
102 return null;
103 }
104
105 // TODO: x86 (no SSE/SSE2) requires x87 FPU to be setup correctly with fldcw
106 const info = FloatInfo.from(T);
107
108 var value: T = 0;
109 if (n.exponent <= info.max_exponent_fast_path) {
110 // normal fast path
111 value = @intToFloat(T, n.mantissa);
112 value = if (n.exponent < 0)
113 value / fastPow10(T, @intCast(usize, -n.exponent))
114 else
115 value * fastPow10(T, @intCast(usize, n.exponent));
116 } else {
117 // disguised fast path
118 const shift = n.exponent - info.max_exponent_fast_path;
119 const mantissa = math.mul(MantissaT, n.mantissa, fastIntPow10(MantissaT, @intCast(usize, shift))) catch return null;
120 if (mantissa > info.max_mantissa_fast_path) {
121 return null;
122 }
123 value = @intToFloat(T, mantissa) * fastPow10(T, info.max_exponent_fast_path);
124 }
125
126 if (n.negative) {
127 value = -value;
128 }
129 return value;
130}
lib/std/fmt/parse_float/convert_hex.zig created+89
......@@ -0,0 +1,89 @@
1//! Conversion of hex-float representation into an accurate value.
2//
3// Derived from golang strconv/atof.go.
4
5const std = @import("std");
6const math = std.math;
7const common = @import("common.zig");
8const Number = common.Number;
9const floatFromUnsigned = common.floatFromUnsigned;
10
11// converts the form 0xMMM.NNNpEEE.
12//
13// MMM.NNN = mantissa
14// EEE = exponent
15//
16// MMM.NNN is stored as an integer, the exponent is offset.
17pub fn convertHex(comptime T: type, n_: Number(T)) T {
18 const MantissaT = common.mantissaType(T);
19 var n = n_;
20
21 if (n.mantissa == 0) {
22 return if (n.negative) -0.0 else 0.0;
23 }
24
25 const max_exp = math.floatExponentMax(T);
26 const min_exp = math.floatExponentMin(T);
27 const mantissa_bits = math.floatMantissaBits(T);
28 const exp_bits = math.floatExponentBits(T);
29 const exp_bias = min_exp - 1;
30
31 // mantissa now implicitly divided by 2^mantissa_bits
32 n.exponent += mantissa_bits;
33
34 // Shift mantissa and exponent to bring representation into float range.
35 // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits.
36 // For rounding, we need two more, where the bottom bit represents
37 // whether that bit or any later bit was non-zero.
38 // (If the mantissa has already lost non-zero bits, trunc is true,
39 // and we OR in a 1 below after shifting left appropriately.)
40 while (n.mantissa != 0 and n.mantissa >> (mantissa_bits + 2) == 0) {
41 n.mantissa <<= 1;
42 n.exponent -= 1;
43 }
44 if (n.many_digits) {
45 n.mantissa |= 1;
46 }
47 while (n.mantissa >> (1 + mantissa_bits + 2) != 0) {
48 n.mantissa = (n.mantissa >> 1) | (n.mantissa & 1);
49 n.exponent += 1;
50 }
51
52 // If exponent is too negative,
53 // denormalize in hopes of making it representable.
54 // (The -2 is for the rounding bits.)
55 while (n.mantissa > 1 and n.exponent < min_exp - 2) {
56 n.mantissa = (n.mantissa >> 1) | (n.mantissa & 1);
57 n.exponent += 1;
58 }
59
60 // Round using two bottom bits.
61 var round = n.mantissa & 3;
62 n.mantissa >>= 2;
63 round |= n.mantissa & 1; // round to even (round up if mantissa is odd)
64 n.exponent += 2;
65 if (round == 3) {
66 n.mantissa += 1;
67 if (n.mantissa == 1 << (1 + mantissa_bits)) {
68 n.mantissa >>= 1;
69 n.exponent += 1;
70 }
71 }
72
73 // Denormal or zero
74 if (n.mantissa >> mantissa_bits == 0) {
75 n.exponent = exp_bias;
76 }
77
78 // Infinity and range error
79 if (n.exponent > max_exp) {
80 return math.inf(T);
81 }
82
83 var bits = n.mantissa & ((1 << mantissa_bits) - 1);
84 bits |= @intCast(MantissaT, (n.exponent - exp_bias) & ((1 << exp_bits) - 1)) << mantissa_bits;
85 if (n.negative) {
86 bits |= 1 << (mantissa_bits + exp_bits);
87 }
88 return floatFromUnsigned(T, MantissaT, bits);
89}
lib/std/fmt/parse_float/convert_slow.zig created+114
......@@ -0,0 +1,114 @@
1const std = @import("std");
2const math = std.math;
3const common = @import("common.zig");
4const BiasedFp = common.BiasedFp;
5const Decimal = @import("decimal.zig").Decimal;
6const mantissaType = common.mantissaType;
7
8const max_shift = 60;
9const num_powers = 19;
10const powers = [_]u8{ 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59 };
11
12pub fn getShift(n: usize) usize {
13 return if (n < num_powers) powers[n] else max_shift;
14}
15
16/// Parse the significant digits and biased, binary exponent of a float.
17///
18/// This is a fallback algorithm that uses a big-integer representation
19/// of the float, and therefore is considerably slower than faster
20/// approximations. However, it will always determine how to round
21/// the significant digits to the nearest machine float, allowing
22/// use to handle near half-way cases.
23///
24/// Near half-way cases are halfway between two consecutive machine floats.
25/// For example, the float `16777217.0` has a bitwise representation of
26/// `100000000000000000000000 1`. Rounding to a single-precision float,
27/// the trailing `1` is truncated. Using round-nearest, tie-even, any
28/// value above `16777217.0` must be rounded up to `16777218.0`, while
29/// any value before or equal to `16777217.0` must be rounded down
30/// to `16777216.0`. These near-halfway conversions therefore may require
31/// a large number of digits to unambiguously determine how to round.
32///
33/// The algorithms described here are based on "Processing Long Numbers Quickly",
34/// available here: <https://arxiv.org/pdf/2101.11408.pdf#section.11>.
35pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) {
36 const MantissaT = mantissaType(T);
37 const min_exponent = -(1 << (math.floatExponentBits(T) - 1)) + 1;
38 const infinite_power = (1 << math.floatExponentBits(T)) - 1;
39 const mantissa_explicit_bits = math.floatMantissaBits(T);
40
41 var d = Decimal(T).parse(s); // no need to recheck underscores
42 if (d.num_digits == 0 or d.decimal_point < Decimal(T).min_exponent) {
43 return BiasedFp(T).zero();
44 } else if (d.decimal_point >= Decimal(T).max_exponent) {
45 return BiasedFp(T).inf(T);
46 }
47
48 var exp2: i32 = 0;
49 // Shift right toward (1/2 .. 1]
50 while (d.decimal_point > 0) {
51 const n = @intCast(usize, d.decimal_point);
52 const shift = getShift(n);
53 d.rightShift(shift);
54 if (d.decimal_point < -Decimal(T).decimal_point_range) {
55 return BiasedFp(T).zero();
56 }
57 exp2 += @intCast(i32, shift);
58 }
59 // Shift left toward (1/2 .. 1]
60 while (d.decimal_point <= 0) {
61 const shift = blk: {
62 if (d.decimal_point == 0) {
63 break :blk switch (d.digits[0]) {
64 5...9 => break,
65 0, 1 => @as(usize, 2),
66 else => 1,
67 };
68 } else {
69 const n = @intCast(usize, -d.decimal_point);
70 break :blk getShift(n);
71 }
72 };
73 d.leftShift(shift);
74 if (d.decimal_point > Decimal(T).decimal_point_range) {
75 return BiasedFp(T).inf(T);
76 }
77 exp2 -= @intCast(i32, shift);
78 }
79 // We are now in the range [1/2 .. 1] but the binary format uses [1 .. 2]
80 exp2 -= 1;
81 while (min_exponent + 1 > exp2) {
82 var n = @intCast(usize, (min_exponent + 1) - exp2);
83 if (n > max_shift) {
84 n = max_shift;
85 }
86 d.rightShift(n);
87 exp2 += @intCast(i32, n);
88 }
89 if (exp2 - min_exponent >= infinite_power) {
90 return BiasedFp(T).inf(T);
91 }
92
93 // Shift the decimal to the hidden bit, and then round the value
94 // to get the high mantissa+1 bits.
95 d.leftShift(mantissa_explicit_bits + 1);
96 var mantissa = d.round();
97 if (mantissa >= (@as(MantissaT, 1) << (mantissa_explicit_bits + 1))) {
98 // Rounding up overflowed to the carry bit, need to
99 // shift back to the hidden bit.
100 d.rightShift(1);
101 exp2 += 1;
102 mantissa = d.round();
103 if ((exp2 - min_exponent) >= infinite_power) {
104 return BiasedFp(T).inf(T);
105 }
106 }
107 var power2 = exp2 - min_exponent;
108 if (mantissa < (@as(MantissaT, 1) << mantissa_explicit_bits)) {
109 power2 -= 1;
110 }
111 // Zero out all the bits above the explicit mantissa bits.
112 mantissa &= (@as(MantissaT, 1) << mantissa_explicit_bits) - 1;
113 return .{ .f = mantissa, .e = power2 };
114}
lib/std/fmt/parse_float/decimal.zig created+493
......@@ -0,0 +1,493 @@
1const std = @import("std");
2const math = std.math;
3const common = @import("common.zig");
4const FloatStream = @import("FloatStream.zig");
5const isEightDigits = @import("common.zig").isEightDigits;
6const mantissaType = common.mantissaType;
7
8// Arbitrary-precision decimal class for fallback algorithms.
9//
10// This is only used if the fast-path (native floats) and
11// the Eisel-Lemire algorithm are unable to unambiguously
12// determine the float.
13//
14// The technique used is "Simple Decimal Conversion", developed
15// by Nigel Tao and Ken Thompson. A detailed description of the
16// algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion",
17// available online: <https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html>.
18//
19// Big-decimal implementation. We do not use the big.Int routines since we only require a maximum
20// fixed region of memory. Further, we require only a small subset of operations.
21//
22// This accepts a floating point parameter and will generate a Decimal which can correctly parse
23// the input with sufficient accuracy. Internally this means either a u64 mantissa (f16, f32 or f64)
24// or a u128 mantissa (f128).
25pub fn Decimal(comptime T: type) type {
26 const MantissaT = mantissaType(T);
27 std.debug.assert(MantissaT == u64 or MantissaT == u128);
28
29 return struct {
30 const Self = @This();
31
32 /// The maximum number of digits required to unambiguously round a float.
33 ///
34 /// For a double-precision IEEE-754 float, this required 767 digits,
35 /// so we store the max digits + 1.
36 ///
37 /// We can exactly represent a float in radix `b` from radix 2 if
38 /// `b` is divisible by 2. This function calculates the exact number of
39 /// digits required to exactly represent that float.
40 ///
41 /// According to the "Handbook of Floating Point Arithmetic",
42 /// for IEEE754, with emin being the min exponent, p2 being the
43 /// precision, and b being the radix, the number of digits follows as:
44 ///
45 /// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋`
46 ///
47 /// For f32, this follows as:
48 /// emin = -126
49 /// p2 = 24
50 ///
51 /// For f64, this follows as:
52 /// emin = -1022
53 /// p2 = 53
54 ///
55 /// For f128, this follows as:
56 /// emin = -16383
57 /// p2 = 112
58 ///
59 /// In Python:
60 /// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))`
61 pub const max_digits = if (MantissaT == u64) 768 else 11564;
62 /// The max digits that can be exactly represented in a 64-bit integer.
63 pub const max_digits_without_overflow = if (MantissaT == u64) 19 else 38;
64 pub const decimal_point_range = if (MantissaT == u64) 2047 else 32767;
65 pub const min_exponent = if (MantissaT == u64) -324 else -4966;
66 pub const max_exponent = if (MantissaT == u64) 310 else 4933;
67 pub const max_decimal_digits = if (MantissaT == u64) 18 else 37;
68
69 /// The number of significant digits in the decimal.
70 num_digits: usize,
71 /// The offset of the decimal point in the significant digits.
72 decimal_point: i32,
73 /// If the number of significant digits stored in the decimal is truncated.
74 truncated: bool,
75 /// buffer of the raw digits, in the range [0, 9].
76 digits: [max_digits]u8,
77
78 pub fn new() Self {
79 return .{
80 .num_digits = 0,
81 .decimal_point = 0,
82 .truncated = false,
83 .digits = [_]u8{0} ** max_digits,
84 };
85 }
86
87 /// Append a digit to the buffer
88 pub fn tryAddDigit(self: *Self, digit: u8) void {
89 if (self.num_digits < max_digits) {
90 self.digits[self.num_digits] = digit;
91 }
92 self.num_digits += 1;
93 }
94
95 /// Trim trailing zeroes from the buffer
96 pub fn trim(self: *Self) void {
97 // All of the following calls to `Self::trim` can't panic because:
98 //
99 // 1. `parse_decimal` sets `num_digits` to a max of `max_digits`.
100 // 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`.
101 // 3. `left_shift` `num_digits` to a max of `max_digits`.
102 //
103 // Trim is only called in `right_shift` and `left_shift`.
104 std.debug.assert(self.num_digits <= max_digits);
105 while (self.num_digits != 0 and self.digits[self.num_digits - 1] == 0) {
106 self.num_digits -= 1;
107 }
108 }
109
110 pub fn round(self: *Self) MantissaT {
111 if (self.num_digits == 0 or self.decimal_point < 0) {
112 return 0;
113 } else if (self.decimal_point > max_decimal_digits) {
114 return math.maxInt(MantissaT);
115 }
116
117 const dp = @intCast(usize, self.decimal_point);
118 var n: MantissaT = 0;
119
120 var i: usize = 0;
121 while (i < dp) : (i += 1) {
122 n *= 10;
123 if (i < self.num_digits) {
124 n += @as(MantissaT, self.digits[i]);
125 }
126 }
127
128 var round_up = false;
129 if (dp < self.num_digits) {
130 round_up = self.digits[dp] >= 5;
131 if (self.digits[dp] == 5 and dp + 1 == self.num_digits) {
132 round_up = self.truncated or ((dp != 0) and (1 & self.digits[dp - 1] != 0));
133 }
134 }
135 if (round_up) {
136 n += 1;
137 }
138 return n;
139 }
140
141 /// Computes decimal * 2^shift.
142 pub fn leftShift(self: *Self, shift: usize) void {
143 if (self.num_digits == 0) {
144 return;
145 }
146 const num_new_digits = self.numberOfDigitsLeftShift(shift);
147 var read_index = self.num_digits;
148 var write_index = self.num_digits + num_new_digits;
149 var n: MantissaT = 0;
150 while (read_index != 0) {
151 read_index -= 1;
152 write_index -= 1;
153 n += math.shl(MantissaT, self.digits[read_index], shift);
154
155 const quotient = n / 10;
156 const remainder = n - (10 * quotient);
157 if (write_index < max_digits) {
158 self.digits[write_index] = @intCast(u8, remainder);
159 } else if (remainder > 0) {
160 self.truncated = true;
161 }
162 n = quotient;
163 }
164 while (n > 0) {
165 write_index -= 1;
166
167 const quotient = n / 10;
168 const remainder = n - (10 * quotient);
169 if (write_index < max_digits) {
170 self.digits[write_index] = @intCast(u8, remainder);
171 } else if (remainder > 0) {
172 self.truncated = true;
173 }
174 n = quotient;
175 }
176
177 self.num_digits += num_new_digits;
178 if (self.num_digits > max_digits) {
179 self.num_digits = max_digits;
180 }
181 self.decimal_point += @intCast(i32, num_new_digits);
182 self.trim();
183 }
184
185 /// Computes decimal * 2^-shift.
186 pub fn rightShift(self: *Self, shift: usize) void {
187 var read_index: usize = 0;
188 var write_index: usize = 0;
189 var n: MantissaT = 0;
190 while (math.shr(MantissaT, n, shift) == 0) {
191 if (read_index < self.num_digits) {
192 n = (10 * n) + self.digits[read_index];
193 read_index += 1;
194 } else if (n == 0) {
195 return;
196 } else {
197 while (math.shr(MantissaT, n, shift) == 0) {
198 n *= 10;
199 read_index += 1;
200 }
201 break;
202 }
203 }
204
205 self.decimal_point -= @intCast(i32, read_index) - 1;
206 if (self.decimal_point < -decimal_point_range) {
207 self.num_digits = 0;
208 self.decimal_point = 0;
209 self.truncated = false;
210 return;
211 }
212
213 const mask = math.shl(MantissaT, 1, shift) - 1;
214 while (read_index < self.num_digits) {
215 const new_digit = @intCast(u8, math.shr(MantissaT, n, shift));
216 n = (10 * (n & mask)) + self.digits[read_index];
217 read_index += 1;
218 self.digits[write_index] = new_digit;
219 write_index += 1;
220 }
221 while (n > 0) {
222 const new_digit = @intCast(u8, math.shr(MantissaT, n, shift));
223 n = 10 * (n & mask);
224 if (write_index < max_digits) {
225 self.digits[write_index] = new_digit;
226 write_index += 1;
227 } else if (new_digit > 0) {
228 self.truncated = true;
229 }
230 }
231 self.num_digits = write_index;
232 self.trim();
233 }
234
235 /// Parse a bit integer representation of the float as a decimal.
236 // We do not verify underscores in this path since these will have been verified
237 // via parse.parseNumber so can assume the number is well-formed.
238 // This code-path does not have to handle hex-floats since these will always be handled via another
239 // function prior to this.
240 pub fn parse(s: []const u8) Self {
241 var d = Self.new();
242 var stream = FloatStream.init(s);
243
244 stream.skipChars2('0', '_');
245 while (stream.scanDigit(10)) |digit| {
246 d.tryAddDigit(digit);
247 }
248
249 if (stream.firstIs('.')) {
250 stream.advance(1);
251 const marker = stream.offsetTrue();
252
253 // Skip leading zeroes
254 if (d.num_digits == 0) {
255 stream.skipChars('0');
256 }
257
258 while (stream.hasLen(8) and d.num_digits + 8 < max_digits) {
259 const v = stream.readU64Unchecked();
260 if (!isEightDigits(v)) {
261 break;
262 }
263 std.mem.writeIntSliceLittle(u64, d.digits[d.num_digits..], v - 0x3030_3030_3030_3030);
264 d.num_digits += 8;
265 stream.advance(8);
266 }
267
268 while (stream.scanDigit(10)) |digit| {
269 d.tryAddDigit(digit);
270 }
271 d.decimal_point = @intCast(i32, marker) - @intCast(i32, stream.offsetTrue());
272 }
273 if (d.num_digits != 0) {
274 // Ignore trailing zeros if any
275 var n_trailing_zeros: usize = 0;
276 var i = stream.offsetTrue() - 1;
277 while (true) {
278 if (s[i] == '0') {
279 n_trailing_zeros += 1;
280 } else if (s[i] != '.') {
281 break;
282 }
283
284 i -= 1;
285 if (i == 0) break;
286 }
287 d.decimal_point += @intCast(i32, n_trailing_zeros);
288 d.num_digits -= n_trailing_zeros;
289 d.decimal_point += @intCast(i32, d.num_digits);
290 if (d.num_digits > max_digits) {
291 d.truncated = true;
292 d.num_digits = max_digits;
293 }
294 }
295 if (stream.firstIsLower('e')) {
296 stream.advance(1);
297 var neg_exp = false;
298 if (stream.firstIs('-')) {
299 neg_exp = true;
300 stream.advance(1);
301 } else if (stream.firstIs('+')) {
302 stream.advance(1);
303 }
304 var exp_num: i32 = 0;
305 while (stream.scanDigit(10)) |digit| {
306 if (exp_num < 0x10000) {
307 exp_num = 10 * exp_num + digit;
308 }
309 }
310 d.decimal_point += if (neg_exp) -exp_num else exp_num;
311 }
312
313 var i = d.num_digits;
314 while (i < max_digits_without_overflow) : (i += 1) {
315 d.digits[i] = 0;
316 }
317
318 return d;
319 }
320
321 // Compute the number decimal digits introduced by a base-2 shift. This is performed
322 // by storing the leading digits of 1/2^i = 5^i and using these along with the cut-off
323 // value to quickly determine the decimal shift from binary.
324 //
325 // See also https://github.com/golang/go/blob/go1.15.3/src/strconv/decimal.go#L163 for
326 // another description of the method.
327 pub fn numberOfDigitsLeftShift(self: *Self, shift: usize) usize {
328 const ShiftCutoff = struct {
329 delta: u8,
330 cutoff: []const u8,
331 };
332
333 // Leading digits of 1/2^i = 5^i.
334 //
335 // ```
336 // import math
337 //
338 // bits = 128
339 // for i in range(bits):
340 // log2 = math.log(2)/math.log(10)
341 // print(f'.{{ .delta = {int(log2*i+1)}, .cutoff = "{5**i}" }}, // {2**i}')
342 // ```
343 const pow2_to_pow5_table = [_]ShiftCutoff{
344 .{ .delta = 0, .cutoff = "" },
345 .{ .delta = 1, .cutoff = "5" }, // 2
346 .{ .delta = 1, .cutoff = "25" }, // 4
347 .{ .delta = 1, .cutoff = "125" }, // 8
348 .{ .delta = 2, .cutoff = "625" }, // 16
349 .{ .delta = 2, .cutoff = "3125" }, // 32
350 .{ .delta = 2, .cutoff = "15625" }, // 64
351 .{ .delta = 3, .cutoff = "78125" }, // 128
352 .{ .delta = 3, .cutoff = "390625" }, // 256
353 .{ .delta = 3, .cutoff = "1953125" }, // 512
354 .{ .delta = 4, .cutoff = "9765625" }, // 1024
355 .{ .delta = 4, .cutoff = "48828125" }, // 2048
356 .{ .delta = 4, .cutoff = "244140625" }, // 4096
357 .{ .delta = 4, .cutoff = "1220703125" }, // 8192
358 .{ .delta = 5, .cutoff = "6103515625" }, // 16384
359 .{ .delta = 5, .cutoff = "30517578125" }, // 32768
360 .{ .delta = 5, .cutoff = "152587890625" }, // 65536
361 .{ .delta = 6, .cutoff = "762939453125" }, // 131072
362 .{ .delta = 6, .cutoff = "3814697265625" }, // 262144
363 .{ .delta = 6, .cutoff = "19073486328125" }, // 524288
364 .{ .delta = 7, .cutoff = "95367431640625" }, // 1048576
365 .{ .delta = 7, .cutoff = "476837158203125" }, // 2097152
366 .{ .delta = 7, .cutoff = "2384185791015625" }, // 4194304
367 .{ .delta = 7, .cutoff = "11920928955078125" }, // 8388608
368 .{ .delta = 8, .cutoff = "59604644775390625" }, // 16777216
369 .{ .delta = 8, .cutoff = "298023223876953125" }, // 33554432
370 .{ .delta = 8, .cutoff = "1490116119384765625" }, // 67108864
371 .{ .delta = 9, .cutoff = "7450580596923828125" }, // 134217728
372 .{ .delta = 9, .cutoff = "37252902984619140625" }, // 268435456
373 .{ .delta = 9, .cutoff = "186264514923095703125" }, // 536870912
374 .{ .delta = 10, .cutoff = "931322574615478515625" }, // 1073741824
375 .{ .delta = 10, .cutoff = "4656612873077392578125" }, // 2147483648
376 .{ .delta = 10, .cutoff = "23283064365386962890625" }, // 4294967296
377 .{ .delta = 10, .cutoff = "116415321826934814453125" }, // 8589934592
378 .{ .delta = 11, .cutoff = "582076609134674072265625" }, // 17179869184
379 .{ .delta = 11, .cutoff = "2910383045673370361328125" }, // 34359738368
380 .{ .delta = 11, .cutoff = "14551915228366851806640625" }, // 68719476736
381 .{ .delta = 12, .cutoff = "72759576141834259033203125" }, // 137438953472
382 .{ .delta = 12, .cutoff = "363797880709171295166015625" }, // 274877906944
383 .{ .delta = 12, .cutoff = "1818989403545856475830078125" }, // 549755813888
384 .{ .delta = 13, .cutoff = "9094947017729282379150390625" }, // 1099511627776
385 .{ .delta = 13, .cutoff = "45474735088646411895751953125" }, // 2199023255552
386 .{ .delta = 13, .cutoff = "227373675443232059478759765625" }, // 4398046511104
387 .{ .delta = 13, .cutoff = "1136868377216160297393798828125" }, // 8796093022208
388 .{ .delta = 14, .cutoff = "5684341886080801486968994140625" }, // 17592186044416
389 .{ .delta = 14, .cutoff = "28421709430404007434844970703125" }, // 35184372088832
390 .{ .delta = 14, .cutoff = "142108547152020037174224853515625" }, // 70368744177664
391 .{ .delta = 15, .cutoff = "710542735760100185871124267578125" }, // 140737488355328
392 .{ .delta = 15, .cutoff = "3552713678800500929355621337890625" }, // 281474976710656
393 .{ .delta = 15, .cutoff = "17763568394002504646778106689453125" }, // 562949953421312
394 .{ .delta = 16, .cutoff = "88817841970012523233890533447265625" }, // 1125899906842624
395 .{ .delta = 16, .cutoff = "444089209850062616169452667236328125" }, // 2251799813685248
396 .{ .delta = 16, .cutoff = "2220446049250313080847263336181640625" }, // 4503599627370496
397 .{ .delta = 16, .cutoff = "11102230246251565404236316680908203125" }, // 9007199254740992
398 .{ .delta = 17, .cutoff = "55511151231257827021181583404541015625" }, // 18014398509481984
399 .{ .delta = 17, .cutoff = "277555756156289135105907917022705078125" }, // 36028797018963968
400 .{ .delta = 17, .cutoff = "1387778780781445675529539585113525390625" }, // 72057594037927936
401 .{ .delta = 18, .cutoff = "6938893903907228377647697925567626953125" }, // 144115188075855872
402 .{ .delta = 18, .cutoff = "34694469519536141888238489627838134765625" }, // 288230376151711744
403 .{ .delta = 18, .cutoff = "173472347597680709441192448139190673828125" }, // 576460752303423488
404 .{ .delta = 19, .cutoff = "867361737988403547205962240695953369140625" }, // 1152921504606846976
405 .{ .delta = 19, .cutoff = "4336808689942017736029811203479766845703125" }, // 2305843009213693952
406 .{ .delta = 19, .cutoff = "21684043449710088680149056017398834228515625" }, // 4611686018427387904
407 .{ .delta = 19, .cutoff = "108420217248550443400745280086994171142578125" }, // 9223372036854775808
408 .{ .delta = 20, .cutoff = "542101086242752217003726400434970855712890625" }, // 18446744073709551616
409 .{ .delta = 20, .cutoff = "2710505431213761085018632002174854278564453125" }, // 36893488147419103232
410 .{ .delta = 20, .cutoff = "13552527156068805425093160010874271392822265625" }, // 73786976294838206464
411 .{ .delta = 21, .cutoff = "67762635780344027125465800054371356964111328125" }, // 147573952589676412928
412 .{ .delta = 21, .cutoff = "338813178901720135627329000271856784820556640625" }, // 295147905179352825856
413 .{ .delta = 21, .cutoff = "1694065894508600678136645001359283924102783203125" }, // 590295810358705651712
414 .{ .delta = 22, .cutoff = "8470329472543003390683225006796419620513916015625" }, // 1180591620717411303424
415 .{ .delta = 22, .cutoff = "42351647362715016953416125033982098102569580078125" }, // 2361183241434822606848
416 .{ .delta = 22, .cutoff = "211758236813575084767080625169910490512847900390625" }, // 4722366482869645213696
417 .{ .delta = 22, .cutoff = "1058791184067875423835403125849552452564239501953125" }, // 9444732965739290427392
418 .{ .delta = 23, .cutoff = "5293955920339377119177015629247762262821197509765625" }, // 18889465931478580854784
419 .{ .delta = 23, .cutoff = "26469779601696885595885078146238811314105987548828125" }, // 37778931862957161709568
420 .{ .delta = 23, .cutoff = "132348898008484427979425390731194056570529937744140625" }, // 75557863725914323419136
421 .{ .delta = 24, .cutoff = "661744490042422139897126953655970282852649688720703125" }, // 151115727451828646838272
422 .{ .delta = 24, .cutoff = "3308722450212110699485634768279851414263248443603515625" }, // 302231454903657293676544
423 .{ .delta = 24, .cutoff = "16543612251060553497428173841399257071316242218017578125" }, // 604462909807314587353088
424 .{ .delta = 25, .cutoff = "82718061255302767487140869206996285356581211090087890625" }, // 1208925819614629174706176
425 .{ .delta = 25, .cutoff = "413590306276513837435704346034981426782906055450439453125" }, // 2417851639229258349412352
426 .{ .delta = 25, .cutoff = "2067951531382569187178521730174907133914530277252197265625" }, // 4835703278458516698824704
427 .{ .delta = 25, .cutoff = "10339757656912845935892608650874535669572651386260986328125" }, // 9671406556917033397649408
428 .{ .delta = 26, .cutoff = "51698788284564229679463043254372678347863256931304931640625" }, // 19342813113834066795298816
429 .{ .delta = 26, .cutoff = "258493941422821148397315216271863391739316284656524658203125" }, // 38685626227668133590597632
430 .{ .delta = 26, .cutoff = "1292469707114105741986576081359316958696581423282623291015625" }, // 77371252455336267181195264
431 .{ .delta = 27, .cutoff = "6462348535570528709932880406796584793482907116413116455078125" }, // 154742504910672534362390528
432 .{ .delta = 27, .cutoff = "32311742677852643549664402033982923967414535582065582275390625" }, // 309485009821345068724781056
433 .{ .delta = 27, .cutoff = "161558713389263217748322010169914619837072677910327911376953125" }, // 618970019642690137449562112
434 .{ .delta = 28, .cutoff = "807793566946316088741610050849573099185363389551639556884765625" }, // 1237940039285380274899124224
435 .{ .delta = 28, .cutoff = "4038967834731580443708050254247865495926816947758197784423828125" }, // 2475880078570760549798248448
436 .{ .delta = 28, .cutoff = "20194839173657902218540251271239327479634084738790988922119140625" }, // 4951760157141521099596496896
437 .{ .delta = 28, .cutoff = "100974195868289511092701256356196637398170423693954944610595703125" }, // 9903520314283042199192993792
438 .{ .delta = 29, .cutoff = "504870979341447555463506281780983186990852118469774723052978515625" }, // 19807040628566084398385987584
439 .{ .delta = 29, .cutoff = "2524354896707237777317531408904915934954260592348873615264892578125" }, // 39614081257132168796771975168
440 .{ .delta = 29, .cutoff = "12621774483536188886587657044524579674771302961744368076324462890625" }, // 79228162514264337593543950336
441 .{ .delta = 30, .cutoff = "63108872417680944432938285222622898373856514808721840381622314453125" }, // 158456325028528675187087900672
442 .{ .delta = 30, .cutoff = "315544362088404722164691426113114491869282574043609201908111572265625" }, // 316912650057057350374175801344
443 .{ .delta = 30, .cutoff = "1577721810442023610823457130565572459346412870218046009540557861328125" }, // 633825300114114700748351602688
444 .{ .delta = 31, .cutoff = "7888609052210118054117285652827862296732064351090230047702789306640625" }, // 1267650600228229401496703205376
445 .{ .delta = 31, .cutoff = "39443045261050590270586428264139311483660321755451150238513946533203125" }, // 2535301200456458802993406410752
446 .{ .delta = 31, .cutoff = "197215226305252951352932141320696557418301608777255751192569732666015625" }, // 5070602400912917605986812821504
447 .{ .delta = 32, .cutoff = "986076131526264756764660706603482787091508043886278755962848663330078125" }, // 10141204801825835211973625643008
448 .{ .delta = 32, .cutoff = "4930380657631323783823303533017413935457540219431393779814243316650390625" }, // 20282409603651670423947251286016
449 .{ .delta = 32, .cutoff = "24651903288156618919116517665087069677287701097156968899071216583251953125" }, // 40564819207303340847894502572032
450 .{ .delta = 32, .cutoff = "123259516440783094595582588325435348386438505485784844495356082916259765625" }, // 81129638414606681695789005144064
451 .{ .delta = 33, .cutoff = "616297582203915472977912941627176741932192527428924222476780414581298828125" }, // 162259276829213363391578010288128
452 .{ .delta = 33, .cutoff = "3081487911019577364889564708135883709660962637144621112383902072906494140625" }, // 324518553658426726783156020576256
453 .{ .delta = 33, .cutoff = "15407439555097886824447823540679418548304813185723105561919510364532470703125" }, // 649037107316853453566312041152512
454 .{ .delta = 34, .cutoff = "77037197775489434122239117703397092741524065928615527809597551822662353515625" }, // 1298074214633706907132624082305024
455 .{ .delta = 34, .cutoff = "385185988877447170611195588516985463707620329643077639047987759113311767578125" }, // 2596148429267413814265248164610048
456 .{ .delta = 34, .cutoff = "1925929944387235853055977942584927318538101648215388195239938795566558837890625" }, // 5192296858534827628530496329220096
457 .{ .delta = 35, .cutoff = "9629649721936179265279889712924636592690508241076940976199693977832794189453125" }, // 10384593717069655257060992658440192
458 .{ .delta = 35, .cutoff = "48148248609680896326399448564623182963452541205384704880998469889163970947265625" }, // 20769187434139310514121985316880384
459 .{ .delta = 35, .cutoff = "240741243048404481631997242823115914817262706026923524404992349445819854736328125" }, // 41538374868278621028243970633760768
460 .{ .delta = 35, .cutoff = "1203706215242022408159986214115579574086313530134617622024961747229099273681640625" }, // 83076749736557242056487941267521536
461 .{ .delta = 36, .cutoff = "6018531076210112040799931070577897870431567650673088110124808736145496368408203125" }, // 166153499473114484112975882535043072
462 .{ .delta = 36, .cutoff = "30092655381050560203999655352889489352157838253365440550624043680727481842041015625" }, // 332306998946228968225951765070086144
463 .{ .delta = 36, .cutoff = "150463276905252801019998276764447446760789191266827202753120218403637409210205078125" }, // 664613997892457936451903530140172288
464 .{ .delta = 37, .cutoff = "752316384526264005099991383822237233803945956334136013765601092018187046051025390625" }, // 1329227995784915872903807060280344576
465 .{ .delta = 37, .cutoff = "3761581922631320025499956919111186169019729781670680068828005460090935230255126953125" }, // 2658455991569831745807614120560689152
466 .{ .delta = 37, .cutoff = "18807909613156600127499784595555930845098648908353400344140027300454676151275634765625" }, // 5316911983139663491615228241121378304
467 .{ .delta = 38, .cutoff = "94039548065783000637498922977779654225493244541767001720700136502273380756378173828125" }, // 10633823966279326983230456482242756608
468 .{ .delta = 38, .cutoff = "470197740328915003187494614888898271127466222708835008603500682511366903781890869140625" }, // 21267647932558653966460912964485513216
469 .{ .delta = 38, .cutoff = "2350988701644575015937473074444491355637331113544175043017503412556834518909454345703125" }, // 42535295865117307932921825928971026432
470 .{ .delta = 38, .cutoff = "11754943508222875079687365372222456778186655567720875215087517062784172594547271728515625" }, // 85070591730234615865843651857942052864
471 .{ .delta = 39, .cutoff = "58774717541114375398436826861112283890933277838604376075437585313920862972736358642578125" }, // 170141183460469231731687303715884105728
472 };
473
474 std.debug.assert(shift < pow2_to_pow5_table.len);
475 const x = pow2_to_pow5_table[shift];
476
477 // Compare leading digits of current to check if lexicographically less than cutoff.
478 for (x.cutoff) |p5, i| {
479 if (i >= self.num_digits) {
480 return x.delta - 1;
481 } else if (self.digits[i] == p5 - '0') { // digits are stored as integers
482 continue;
483 } else if (self.digits[i] < p5 - '0') {
484 return x.delta - 1;
485 } else {
486 return x.delta;
487 }
488 return x.delta;
489 }
490 return x.delta;
491 }
492 };
493}
lib/std/fmt/parse_float/parse.zig created+293
......@@ -0,0 +1,293 @@
1const std = @import("std");
2const common = @import("common.zig");
3const FloatStream = @import("FloatStream.zig");
4const isEightDigits = common.isEightDigits;
5const Number = common.Number;
6
7/// Parse 8 digits, loaded as bytes in little-endian order.
8///
9/// This uses the trick where every digit is in [0x030, 0x39],
10/// and therefore can be parsed in 3 multiplications, much
11/// faster than the normal 8.
12///
13/// This is based off the algorithm described in "Fast numeric string to
14/// int", available here: <https://johnnylee-sde.github.io/Fast-numeric-string-to-int/>.
15fn parse8Digits(v_: u64) u64 {
16 var v = v_;
17 const mask = 0x0000_00ff_0000_00ff;
18 const mul1 = 0x000f_4240_0000_0064;
19 const mul2 = 0x0000_2710_0000_0001;
20 v -= 0x3030_3030_3030_3030;
21 v = (v * 10) + (v >> 8); // will not overflow, fits in 63 bits
22 const v1 = (v & mask) *% mul1;
23 const v2 = ((v >> 16) & mask) *% mul2;
24 return @as(u64, @truncate(u32, (v1 +% v2) >> 32));
25}
26
27/// Parse digits until a non-digit character is found.
28fn tryParseDigits(comptime T: type, stream: *FloatStream, x: *T, comptime base: u8) void {
29 // Try to parse 8 digits at a time, using an optimized algorithm.
30 // This only supports decimal digits.
31 if (base == 10) {
32 while (stream.hasLen(8)) {
33 const v = stream.readU64Unchecked();
34 if (!isEightDigits(v)) {
35 break;
36 }
37
38 x.* = x.* *% 1_0000_0000 +% parse8Digits(v);
39 stream.advance(8);
40 }
41 }
42
43 while (stream.scanDigit(base)) |digit| {
44 x.* *%= base;
45 x.* +%= digit;
46 }
47}
48
49fn min_n_digit_int(comptime T: type, digit_count: usize) T {
50 var n: T = 1;
51 var i: usize = 1;
52 while (i < digit_count) : (i += 1) n *= 10;
53 return n;
54}
55
56/// Parse up to N digits
57fn tryParseNDigits(comptime T: type, stream: *FloatStream, x: *T, comptime base: u8, comptime n: usize) void {
58 while (x.* < min_n_digit_int(T, n)) {
59 if (stream.scanDigit(base)) |digit| {
60 x.* *%= base;
61 x.* +%= digit;
62 } else {
63 break;
64 }
65 }
66}
67
68/// Parse the scientific notation component of a float.
69fn parseScientific(stream: *FloatStream) ?i64 {
70 var exponent: i64 = 0;
71 var negative = false;
72
73 if (stream.first()) |c| {
74 negative = c == '-';
75 if (c == '-' or c == '+') {
76 stream.advance(1);
77 }
78 }
79 if (stream.firstIsDigit(10)) {
80 while (stream.scanDigit(10)) |digit| {
81 // no overflows here, saturate well before overflow
82 if (exponent < 0x1000_0000) {
83 exponent = 10 * exponent + digit;
84 }
85 }
86
87 return if (negative) -exponent else exponent;
88 }
89
90 return null;
91}
92
93const ParseInfo = struct {
94 // 10 or 16
95 base: u8,
96 // 10^19 fits in u64, 16^16 fits in u64
97 max_mantissa_digits: usize,
98 // e.g. e or p (E and P also checked)
99 exp_char_lower: u8,
100};
101
102fn parsePartialNumberBase(comptime T: type, stream: *FloatStream, negative: bool, n: *usize, comptime info: ParseInfo) ?Number(T) {
103 const MantissaT = common.mantissaType(T);
104
105 // parse initial digits before dot
106 var mantissa: MantissaT = 0;
107 tryParseDigits(MantissaT, stream, &mantissa, info.base);
108 var int_end = stream.offsetTrue();
109 var n_digits = @intCast(isize, stream.offsetTrue());
110
111 // handle dot with the following digits
112 var exponent: i64 = 0;
113 if (stream.firstIs('.')) {
114 stream.advance(1);
115 const marker = stream.offsetTrue();
116 tryParseDigits(MantissaT, stream, &mantissa, info.base);
117 const n_after_dot = stream.offsetTrue() - marker;
118 exponent = -@intCast(i64, n_after_dot);
119 n_digits += @intCast(isize, n_after_dot);
120 }
121
122 // adjust required shift to offset mantissa for base-16 (2^4)
123 if (info.base == 16) {
124 exponent *= 4;
125 }
126
127 if (n_digits == 0) {
128 return null;
129 }
130
131 // handle scientific format
132 var exp_number: i64 = 0;
133 if (stream.firstIsLower(info.exp_char_lower)) {
134 stream.advance(1);
135 exp_number = parseScientific(stream) orelse return null;
136 exponent += exp_number;
137 }
138
139 const len = stream.offset; // length must be complete parsed length
140 n.* = len;
141
142 if (stream.underscore_count > 0 and !validUnderscores(stream.slice, info.base)) {
143 return null;
144 }
145
146 // common case with not many digits
147 if (n_digits <= info.max_mantissa_digits) {
148 return Number(T){
149 .exponent = exponent,
150 .mantissa = mantissa,
151 .negative = negative,
152 .many_digits = false,
153 .hex = info.base == 16,
154 };
155 }
156
157 n_digits -= info.max_mantissa_digits;
158 var many_digits = false;
159 stream.reset(); // re-parse from beginning
160 while (stream.firstIs3('0', '.', '_')) {
161 // '0' = '.' + 2
162 const next = stream.firstUnchecked();
163 if (next != '_') {
164 n_digits -= @intCast(isize, next -| ('0' - 1));
165 } else {
166 stream.underscore_count += 1;
167 }
168 stream.advance(1);
169 }
170 if (n_digits > 0) {
171 // at this point we have more than max_mantissa_digits significant digits, let's try again
172 many_digits = true;
173 mantissa = 0;
174 stream.reset();
175 tryParseNDigits(MantissaT, stream, &mantissa, info.base, info.max_mantissa_digits);
176
177 exponent = blk: {
178 if (mantissa >= min_n_digit_int(MantissaT, info.max_mantissa_digits)) {
179 // big int
180 break :blk @intCast(i64, int_end) - @intCast(i64, stream.offsetTrue());
181 } else {
182 // the next byte must be present and be '.'
183 // We know this is true because we had more than 19
184 // digits previously, so we overflowed a 64-bit integer,
185 // but parsing only the integral digits produced less
186 // than 19 digits. That means we must have a decimal
187 // point, and at least 1 fractional digit.
188 stream.advance(1);
189 var marker = stream.offsetTrue();
190 tryParseNDigits(MantissaT, stream, &mantissa, info.base, info.max_mantissa_digits);
191 break :blk @intCast(i64, marker) - @intCast(i64, stream.offsetTrue());
192 }
193 };
194 // add back the explicit part
195 exponent += exp_number;
196 }
197
198 return Number(T){
199 .exponent = exponent,
200 .mantissa = mantissa,
201 .negative = negative,
202 .many_digits = many_digits,
203 .hex = info.base == 16,
204 };
205}
206
207/// Parse a partial, non-special floating point number.
208///
209/// This creates a representation of the float as the
210/// significant digits and the decimal exponent.
211fn parsePartialNumber(comptime T: type, s: []const u8, negative: bool, n: *usize) ?Number(T) {
212 std.debug.assert(s.len != 0);
213 var stream = FloatStream.init(s);
214 const MantissaT = common.mantissaType(T);
215
216 if (stream.hasLen(2) and stream.atUnchecked(0) == '0' and std.ascii.toLower(stream.atUnchecked(1)) == 'x') {
217 stream.advance(2);
218 return parsePartialNumberBase(T, &stream, negative, n, .{
219 .base = 16,
220 .max_mantissa_digits = if (MantissaT == u64) 16 else 32,
221 .exp_char_lower = 'p',
222 });
223 } else {
224 return parsePartialNumberBase(T, &stream, negative, n, .{
225 .base = 10,
226 .max_mantissa_digits = if (MantissaT == u64) 19 else 38,
227 .exp_char_lower = 'e',
228 });
229 }
230}
231
232pub fn parseNumber(comptime T: type, s: []const u8, negative: bool) ?Number(T) {
233 var consumed: usize = 0;
234 if (parsePartialNumber(T, s, negative, &consumed)) |number| {
235 // must consume entire float (no trailing data)
236 if (s.len == consumed) {
237 return number;
238 }
239 }
240 return null;
241}
242
243fn parsePartialInfOrNan(comptime T: type, s: []const u8, n: *usize) ?T {
244 // inf/infinity; infxxx should only consume inf.
245 if (std.ascii.startsWithIgnoreCase(s, "inf")) {
246 n.* = 3;
247 if (std.ascii.startsWithIgnoreCase(s[3..], "inity")) {
248 n.* = 8;
249 }
250 return std.math.inf(T);
251 }
252
253 if (std.ascii.startsWithIgnoreCase(s, "nan")) {
254 n.* = 3;
255 return std.math.nan(T);
256 }
257
258 return null;
259}
260
261pub fn parseInfOrNan(comptime T: type, s: []const u8, negative: bool) ?T {
262 var consumed: usize = 0;
263 if (parsePartialInfOrNan(T, s, &consumed)) |special| {
264 if (s.len == consumed) {
265 if (negative) {
266 return -1 * special;
267 }
268 return special;
269 }
270 }
271 return null;
272}
273
274pub fn validUnderscores(s: []const u8, comptime base: u8) bool {
275 var i: usize = 0;
276 while (i < s.len) : (i += 1) {
277 if (s[i] == '_') {
278 // underscore at start of end
279 if (i == 0 or i + 1 == s.len) {
280 return false;
281 }
282 // consecutive underscores
283 if (!common.isDigit(s[i - 1], base) or !common.isDigit(s[i + 1], base)) {
284 return false;
285 }
286
287 // next is guaranteed a digit, skip an extra
288 i += 1;
289 }
290 }
291
292 return true;
293}
lib/std/fmt/parse_float/parse_float.zig created+64
......@@ -0,0 +1,64 @@
1const std = @import("std");
2const parse = @import("parse.zig");
3const parseNumber = parse.parseNumber;
4const parseInfOrNan = parse.parseInfOrNan;
5const convertFast = @import("convert_fast.zig").convertFast;
6const convertEiselLemire = @import("convert_eisel_lemire.zig").convertEiselLemire;
7const convertSlow = @import("convert_slow.zig").convertSlow;
8const convertHex = @import("convert_hex.zig").convertHex;
9
10const optimize = true;
11
12pub const ParseFloatError = error{
13 InvalidCharacter,
14};
15
16pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T {
17 if (s.len == 0) {
18 return error.InvalidCharacter;
19 }
20
21 var i: usize = 0;
22 const negative = s[i] == '-';
23 if (s[i] == '-' or s[i] == '+') {
24 i += 1;
25 }
26 if (s.len == i) {
27 return error.InvalidCharacter;
28 }
29
30 const n = parse.parseNumber(T, s[i..], negative) orelse {
31 return parse.parseInfOrNan(T, s[i..], negative) orelse error.InvalidCharacter;
32 };
33
34 if (n.hex) {
35 return convertHex(T, n);
36 }
37
38 if (optimize) {
39 if (convertFast(T, n)) |f| {
40 return f;
41 }
42
43 if (T == f16 or T == f32 or T == f64) {
44 // If significant digits were truncated, then we can have rounding error
45 // only if `mantissa + 1` produces a different result. We also avoid
46 // redundantly using the Eisel-Lemire algorithm if it was unable to
47 // correctly round on the first pass.
48 if (convertEiselLemire(T, n.exponent, n.mantissa)) |bf| {
49 if (!n.many_digits) {
50 return bf.toFloat(T, n.negative);
51 }
52 if (convertEiselLemire(T, n.exponent, n.mantissa + 1)) |bf2| {
53 if (bf.eql(bf2)) {
54 return bf.toFloat(T, n.negative);
55 }
56 }
57 }
58 }
59 }
60
61 // Unable to correctly round the float using the Eisel-Lemire algorithm.
62 // Fallback to a slower, but always correct algorithm.
63 return convertSlow(T, s[i..]).toFloat(T, negative);
64}
lib/std/fmt/parse_hex_float.zig deleted-347
......@@ -1,347 +0,0 @@
1// The rounding logic is inspired by LLVM's APFloat and Go's atofHex
2// implementation.
3
4const std = @import("std");
5const ascii = std.ascii;
6const fmt = std.fmt;
7const math = std.math;
8const testing = std.testing;
9
10const assert = std.debug.assert;
11
12pub fn parseHexFloat(comptime T: type, s: []const u8) !T {
13 assert(@typeInfo(T) == .Float);
14
15 const TBits = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
16
17 const mantissa_bits = math.floatMantissaBits(T);
18 const exponent_bits = math.floatExponentBits(T);
19 const exponent_min = math.floatExponentMin(T);
20 const exponent_max = math.floatExponentMax(T);
21
22 const exponent_bias = exponent_max;
23 const sign_shift = mantissa_bits + exponent_bits;
24
25 if (s.len == 0)
26 return error.InvalidCharacter;
27
28 if (ascii.eqlIgnoreCase(s, "nan")) {
29 return math.nan(T);
30 } else if (ascii.eqlIgnoreCase(s, "inf") or ascii.eqlIgnoreCase(s, "+inf")) {
31 return math.inf(T);
32 } else if (ascii.eqlIgnoreCase(s, "-inf")) {
33 return -math.inf(T);
34 }
35
36 var negative: bool = false;
37 var exp_negative: bool = false;
38
39 var mantissa: u128 = 0;
40 var exponent: i16 = 0;
41 var frac_scale: i16 = 0;
42
43 const State = enum {
44 MaybeSign,
45 Prefix,
46 LeadingIntegerDigit,
47 IntegerDigit,
48 MaybeDot,
49 LeadingFractionDigit,
50 FractionDigit,
51 ExpPrefix,
52 MaybeExpSign,
53 ExpDigit,
54 };
55
56 var state = State.MaybeSign;
57
58 var i: usize = 0;
59 while (i < s.len) {
60 const c = s[i];
61
62 switch (state) {
63 .MaybeSign => {
64 state = .Prefix;
65
66 if (c == '+') {
67 i += 1;
68 } else if (c == '-') {
69 negative = true;
70 i += 1;
71 }
72 },
73 .Prefix => {
74 state = .LeadingIntegerDigit;
75
76 // Match both 0x and 0X.
77 if (i + 2 > s.len or s[i] != '0' or s[i + 1] | 32 != 'x')
78 return error.InvalidCharacter;
79 i += 2;
80 },
81 .LeadingIntegerDigit => {
82 if (c == '0') {
83 // Skip leading zeros.
84 i += 1;
85 } else if (c == '_') {
86 return error.InvalidCharacter;
87 } else {
88 state = .IntegerDigit;
89 }
90 },
91 .IntegerDigit => {
92 if (ascii.isXDigit(c)) {
93 if (mantissa >= math.maxInt(u128) / 16)
94 return error.Overflow;
95 mantissa *%= 16;
96 mantissa += try fmt.charToDigit(c, 16);
97 i += 1;
98 } else if (c == '_') {
99 i += 1;
100 } else {
101 state = .MaybeDot;
102 }
103 },
104 .MaybeDot => {
105 if (c == '.') {
106 state = .LeadingFractionDigit;
107 i += 1;
108 } else state = .ExpPrefix;
109 },
110 .LeadingFractionDigit => {
111 if (c == '_') {
112 return error.InvalidCharacter;
113 } else state = .FractionDigit;
114 },
115 .FractionDigit => {
116 if (ascii.isXDigit(c)) {
117 if (mantissa < math.maxInt(u128) / 16) {
118 mantissa *%= 16;
119 mantissa +%= try fmt.charToDigit(c, 16);
120 frac_scale += 1;
121 } else if (c != '0') {
122 return error.Overflow;
123 }
124 i += 1;
125 } else if (c == '_') {
126 i += 1;
127 } else {
128 state = .ExpPrefix;
129 }
130 },
131 .ExpPrefix => {
132 state = .MaybeExpSign;
133 // Match both p and P.
134 if (c | 32 != 'p')
135 return error.InvalidCharacter;
136 i += 1;
137 },
138 .MaybeExpSign => {
139 state = .ExpDigit;
140
141 if (c == '+') {
142 i += 1;
143 } else if (c == '-') {
144 exp_negative = true;
145 i += 1;
146 }
147 },
148 .ExpDigit => {
149 if (ascii.isXDigit(c)) {
150 if (exponent >= math.maxInt(i16) / 10)
151 return error.Overflow;
152 exponent *%= 10;
153 exponent +%= try fmt.charToDigit(c, 10);
154 i += 1;
155 } else if (c == '_') {
156 i += 1;
157 } else {
158 return error.InvalidCharacter;
159 }
160 },
161 }
162 }
163
164 if (exp_negative)
165 exponent *= -1;
166
167 // Bring the decimal part to the left side of the decimal dot.
168 exponent -= frac_scale * 4;
169
170 if (mantissa == 0) {
171 // Signed zero.
172 return if (negative) -0.0 else 0.0;
173 }
174
175 // Divide by 2^mantissa_bits to right-align the mantissa in the fractional
176 // part.
177 exponent += mantissa_bits;
178
179 // Keep around two extra bits to correctly round any value that doesn't fit
180 // the available mantissa bits. The result LSB serves as Guard bit, the
181 // following one is the Round bit and the last one is the Sticky bit,
182 // computed by OR-ing all the dropped bits.
183
184 // Normalize by aligning the implicit one bit.
185 while (mantissa >> (mantissa_bits + 2) == 0) {
186 mantissa <<= 1;
187 exponent -= 1;
188 }
189
190 // Normalize again by dropping the excess precision.
191 // Note that the discarded bits are folded into the Sticky bit.
192 while (mantissa >> (mantissa_bits + 2 + 1) != 0) {
193 mantissa = mantissa >> 1 | (mantissa & 1);
194 exponent += 1;
195 }
196
197 // Very small numbers can be possibly represented as denormals, reduce the
198 // exponent as much as possible.
199 while (mantissa != 0 and exponent < exponent_min - 2) {
200 mantissa = mantissa >> 1 | (mantissa & 1);
201 exponent += 1;
202 }
203
204 // Whenever the guard bit is one (G=1) and:
205 // - we've truncated more than 0.5ULP (R=S=1)
206 // - we've truncated exactly 0.5ULP (R=1 S=0)
207 // Were are going to increase the mantissa (round up)
208 const guard_bit_and_half_or_more = (mantissa & 0b110) == 0b110;
209 mantissa >>= 2;
210 exponent += 2;
211
212 if (guard_bit_and_half_or_more) {
213 mantissa += 1;
214 }
215
216 if (mantissa == (1 << (mantissa_bits + 1))) {
217 // Renormalize, if the exponent overflows we'll catch that below.
218 mantissa >>= 1;
219 exponent += 1;
220 }
221
222 if (mantissa >> mantissa_bits == 0) {
223 // This is a denormal number, the biased exponent is zero.
224 exponent = -exponent_bias;
225 }
226
227 if (exponent > exponent_max) {
228 // Overflow, return +inf.
229 return math.inf(T);
230 }
231
232 // Remove the implicit bit.
233 mantissa &= @as(u128, (1 << mantissa_bits) - 1);
234
235 const raw: TBits =
236 (if (negative) @as(TBits, 1) << sign_shift else 0) |
237 @as(TBits, @bitCast(u16, exponent + exponent_bias)) << mantissa_bits |
238 @truncate(TBits, mantissa);
239
240 return @bitCast(T, raw);
241}
242
243test "special" {
244 try testing.expect(math.isNan(try parseHexFloat(f32, "nAn")));
245 try testing.expect(math.isPositiveInf(try parseHexFloat(f32, "iNf")));
246 try testing.expect(math.isPositiveInf(try parseHexFloat(f32, "+Inf")));
247 try testing.expect(math.isNegativeInf(try parseHexFloat(f32, "-iNf")));
248}
249test "zero" {
250 try testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "0x0"));
251 try testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "-0x0"));
252 try testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "0x0p42"));
253 try testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "-0x0.00000p42"));
254 try testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "0x0.00000p666"));
255}
256
257test "f16" {
258 const Case = struct { s: []const u8, v: f16 };
259 const cases: []const Case = &[_]Case{
260 .{ .s = "0x1p0", .v = 1.0 },
261 .{ .s = "-0x1p-1", .v = -0.5 },
262 .{ .s = "0x10p+10", .v = 16384.0 },
263 .{ .s = "0x10p-10", .v = 0.015625 },
264 // Max normalized value.
265 .{ .s = "0x1.ffcp+15", .v = math.floatMax(f16) },
266 .{ .s = "-0x1.ffcp+15", .v = -math.floatMax(f16) },
267 // Min normalized value.
268 .{ .s = "0x1p-14", .v = math.floatMin(f16) },
269 .{ .s = "-0x1p-14", .v = -math.floatMin(f16) },
270 // Min denormal value.
271 .{ .s = "0x1p-24", .v = math.floatTrueMin(f16) },
272 .{ .s = "-0x1p-24", .v = -math.floatTrueMin(f16) },
273 };
274
275 for (cases) |case| {
276 try testing.expectEqual(case.v, try parseHexFloat(f16, case.s));
277 }
278}
279test "f32" {
280 const Case = struct { s: []const u8, v: f32 };
281 const cases: []const Case = &[_]Case{
282 .{ .s = "0x1p0", .v = 1.0 },
283 .{ .s = "-0x1p-1", .v = -0.5 },
284 .{ .s = "0x10p+10", .v = 16384.0 },
285 .{ .s = "0x10p-10", .v = 0.015625 },
286 .{ .s = "0x0.ffffffp128", .v = 0x0.ffffffp128 },
287 .{ .s = "0x0.1234570p-125", .v = 0x0.1234570p-125 },
288 // Max normalized value.
289 .{ .s = "0x1.fffffeP+127", .v = math.floatMax(f32) },
290 .{ .s = "-0x1.fffffeP+127", .v = -math.floatMax(f32) },
291 // Min normalized value.
292 .{ .s = "0x1p-126", .v = math.floatMin(f32) },
293 .{ .s = "-0x1p-126", .v = -math.floatMin(f32) },
294 // Min denormal value.
295 .{ .s = "0x1P-149", .v = math.floatTrueMin(f32) },
296 .{ .s = "-0x1P-149", .v = -math.floatTrueMin(f32) },
297 };
298
299 for (cases) |case| {
300 try testing.expectEqual(case.v, try parseHexFloat(f32, case.s));
301 }
302}
303test "f64" {
304 const Case = struct { s: []const u8, v: f64 };
305 const cases: []const Case = &[_]Case{
306 .{ .s = "0x1p0", .v = 1.0 },
307 .{ .s = "-0x1p-1", .v = -0.5 },
308 .{ .s = "0x10p+10", .v = 16384.0 },
309 .{ .s = "0x10p-10", .v = 0.015625 },
310 // Max normalized value.
311 .{ .s = "0x1.fffffffffffffp+1023", .v = math.floatMax(f64) },
312 .{ .s = "-0x1.fffffffffffffp1023", .v = -math.floatMax(f64) },
313 // Min normalized value.
314 .{ .s = "0x1p-1022", .v = math.floatMin(f64) },
315 .{ .s = "-0x1p-1022", .v = -math.floatMin(f64) },
316 // Min denormalized value.
317 .{ .s = "0x1p-1074", .v = math.floatTrueMin(f64) },
318 .{ .s = "-0x1p-1074", .v = -math.floatTrueMin(f64) },
319 };
320
321 for (cases) |case| {
322 try testing.expectEqual(case.v, try parseHexFloat(f64, case.s));
323 }
324}
325test "f128" {
326 const Case = struct { s: []const u8, v: f128 };
327 const cases: []const Case = &[_]Case{
328 .{ .s = "0x1p0", .v = 1.0 },
329 .{ .s = "-0x1p-1", .v = -0.5 },
330 .{ .s = "0x10p+10", .v = 16384.0 },
331 .{ .s = "0x10p-10", .v = 0.015625 },
332 // Max normalized value.
333 .{ .s = "0xf.fffffffffffffffffffffffffff8p+16380", .v = math.floatMax(f128) },
334 .{ .s = "-0xf.fffffffffffffffffffffffffff8p+16380", .v = -math.floatMax(f128) },
335 // Min normalized value.
336 .{ .s = "0x1p-16382", .v = math.floatMin(f128) },
337 .{ .s = "-0x1p-16382", .v = -math.floatMin(f128) },
338 // // Min denormalized value.
339 .{ .s = "0x1p-16494", .v = math.floatTrueMin(f128) },
340 .{ .s = "-0x1p-16494", .v = -math.floatTrueMin(f128) },
341 .{ .s = "0x1.edcb34a235253948765432134674fp-1", .v = 0x1.edcb34a235253948765432134674fp-1 },
342 };
343
344 for (cases) |case| {
345 try testing.expectEqual(@bitCast(u128, case.v), @bitCast(u128, try parseHexFloat(f128, case.s)));
346 }
347}