authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2024-03-21 13:57:57+13:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-03-21 17:10:41+02:00
log31791ae15bfa8590cb235ce9d7c87a97d5136eef
treebf981a8a7b4afbb4edc63e9d44fcac20fd555d3b
parentafdc41cfd61db23f545d9239b61695e2ae991713

rename ryu128 -> format_float

Symmetry with parse_float and to hide the implementation from the user. Additionally, we expose the entire namespace and provide some aliases so everything is available to a user. Closes #19366

4 files changed, 1150 insertions(+), 1147 deletions(-)

CMakeLists.txt+1-1
......@@ -235,7 +235,7 @@ set(ZIG_STAGE2_SOURCES
235235 "${CMAKE_SOURCE_DIR}/lib/std/elf.zig"
236236 "${CMAKE_SOURCE_DIR}/lib/std/fifo.zig"
237237 "${CMAKE_SOURCE_DIR}/lib/std/fmt.zig"
238 "${CMAKE_SOURCE_DIR}/lib/std/fmt/ryu128.zig"
238 "${CMAKE_SOURCE_DIR}/lib/std/fmt/format_float.zig"
239239 "${CMAKE_SOURCE_DIR}/lib/std/fmt/parse_float.zig"
240240 "${CMAKE_SOURCE_DIR}/lib/std/fs.zig"
241241 "${CMAKE_SOURCE_DIR}/lib/std/fs/AtomicFile.zig"
lib/std/fmt.zig+10-7
......@@ -9,7 +9,6 @@ const assert = std.debug.assert;
99const mem = std.mem;
1010const unicode = std.unicode;
1111const meta = std.meta;
12const ryu128 = @import("fmt/ryu128.zig");
1312const lossyCast = std.math.lossyCast;
1413const expectFmt = std.testing.expectFmt;
1514
......@@ -757,21 +756,25 @@ pub fn formatIntValue(
757756 return formatInt(int_value, base, case, options, writer);
758757}
759758
759pub const format_float = @import("fmt/format_float.zig");
760pub const formatFloat = format_float.formatFloat;
761pub const FormatFloatError = format_float.FormatError;
762
760763fn formatFloatValue(
761764 value: anytype,
762765 comptime fmt: []const u8,
763766 options: FormatOptions,
764767 writer: anytype,
765768) !void {
766 var buf: [ryu128.bufferSize(.decimal, f64)]u8 = undefined;
769 var buf: [format_float.bufferSize(.decimal, f64)]u8 = undefined;
767770
768771 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
769 const s = ryu128.format(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) {
772 const s = formatFloat(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) {
770773 error.BufferTooSmall => "(float)",
771774 };
772775 return formatBuf(s, options, writer);
773776 } else if (comptime std.mem.eql(u8, fmt, "d")) {
774 const s = ryu128.format(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
777 const s = formatFloat(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
775778 error.BufferTooSmall => "(float)",
776779 };
777780 return formatBuf(s, options, writer);
......@@ -787,7 +790,7 @@ fn formatFloatValue(
787790}
788791
789792test {
790 _ = &ryu128;
793 _ = &format_float;
791794}
792795
793796pub const Case = enum { lower, upper };
......@@ -890,7 +893,7 @@ fn formatSizeImpl(comptime base: comptime_int) type {
890893 return formatBuf("0B", options, writer);
891894 }
892895 // The worst case in terms of space needed is 32 bytes + 3 for the suffix.
893 var buf: [ryu128.min_buffer_size + 3]u8 = undefined;
896 var buf: [format_float.min_buffer_size + 3]u8 = undefined;
894897
895898 const mags_si = " kMGTPEZY";
896899 const mags_iec = " KMGTPEZY";
......@@ -908,7 +911,7 @@ fn formatSizeImpl(comptime base: comptime_int) type {
908911 else => unreachable,
909912 };
910913
911 const s = ryu128.format(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
914 const s = formatFloat(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
912915 error.BufferTooSmall => unreachable,
913916 };
914917
lib/std/fmt/format_float.zig created+1139
......@@ -0,0 +1,1139 @@
1//! This file implements the ryu floating point conversion algorithm:
2//! https://dl.acm.org/doi/pdf/10.1145/3360595
3
4const std = @import("std");
5const expectFmt = std.testing.expectFmt;
6
7const special_exponent = 0x7fffffff;
8
9/// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will
10/// additionally be performed if more bytes are required.
11pub const min_buffer_size = 53;
12
13/// Returns the minimum buffer size needed to print every float of a specific type and format.
14pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int {
15 comptime std.debug.assert(@typeInfo(T) == .Float);
16 return switch (mode) {
17 .scientific => 53,
18 // Based on minimum subnormal values.
19 .decimal => switch (@bitSizeOf(T)) {
20 16 => @max(15, min_buffer_size),
21 32 => 55,
22 64 => 347,
23 80 => 4996,
24 128 => 5011,
25 else => unreachable,
26 },
27 };
28}
29
30pub const FormatError = error{
31 BufferTooSmall,
32};
33
34pub const Format = enum {
35 scientific,
36 decimal,
37};
38
39pub const FormatOptions = struct {
40 mode: Format = .scientific,
41 precision: ?usize = null,
42};
43
44/// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing
45/// the string representation.
46///
47/// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat
48/// unambiguously.
49///
50/// Scientific mode is recommended generally as the output is more compact and any type can be
51/// written in full precision using a buffer of only `min_buffer_size`.
52///
53/// When printing full precision decimals, use `bufferSize` to get the required space. It is
54/// recommended to bound decimal output with a fixed precision to reduce the required buffer size.
55pub fn formatFloat(buf: []u8, v_: anytype, options: FormatOptions) FormatError![]const u8 {
56 const v = switch (@TypeOf(v_)) {
57 // comptime_float internally is a f128; this preserves precision.
58 comptime_float => @as(f128, v_),
59 else => v_,
60 };
61
62 const T = @TypeOf(v);
63 comptime std.debug.assert(@typeInfo(T) == .Float);
64 const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
65
66 const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0;
67 const d = binaryToDecimal(@as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit);
68
69 return switch (options.mode) {
70 .scientific => formatScientific(buf, d, options.precision),
71 .decimal => formatDecimal(buf, d, options.precision),
72 };
73}
74
75pub const FloatDecimal128 = struct {
76 mantissa: u128,
77 exponent: i32,
78 sign: bool,
79};
80
81fn copySpecialStr(buf: []u8, f: FloatDecimal128) []const u8 {
82 if (f.sign) {
83 buf[0] = '-';
84 }
85 const offset: usize = @intFromBool(f.sign);
86 if (f.mantissa != 0) {
87 @memcpy(buf[offset..][0..3], "nan");
88 return buf[0 .. 3 + offset];
89 }
90 @memcpy(buf[offset..][0..3], "inf");
91 return buf[0 .. 3 + offset];
92}
93
94fn writeDecimal(buf: []u8, value: anytype, count: usize) void {
95 var i: usize = 0;
96
97 while (i + 2 < count) : (i += 2) {
98 const c: u8 = @intCast(value.* % 100);
99 value.* /= 100;
100 const d = std.fmt.digits2(c);
101 buf[count - i - 1] = d[1];
102 buf[count - i - 2] = d[0];
103 }
104
105 while (i < count) : (i += 1) {
106 const c: u8 = @intCast(value.* % 10);
107 value.* /= 10;
108 buf[count - i - 1] = '0' + c;
109 }
110}
111
112fn isPowerOf10(n_: u128) bool {
113 var n = n_;
114 while (n != 0) : (n /= 10) {
115 if (n % 10 != 0) return false;
116 }
117 return true;
118}
119
120const RoundMode = enum {
121 /// 1234.56 = precision 2
122 decimal,
123 /// 1.23456e3 = precision 5
124 scientific,
125};
126
127fn round(f: FloatDecimal128, mode: RoundMode, precision: usize) FloatDecimal128 {
128 var round_digit: usize = 0;
129 var output = f.mantissa;
130 var exp = f.exponent;
131 const olength = decimalLength(output);
132
133 switch (mode) {
134 .decimal => {
135 if (f.exponent > 0) {
136 round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent));
137 } else {
138 const min_exp_required = @as(usize, @intCast(-f.exponent));
139 if (precision + olength > min_exp_required) {
140 round_digit = precision + olength - min_exp_required;
141 }
142 }
143 },
144 .scientific => {
145 round_digit = 1 + precision;
146 },
147 }
148
149 if (round_digit < olength) {
150 var nlength = olength;
151 for (round_digit + 1..olength) |_| {
152 output /= 10;
153 exp += 1;
154 nlength -= 1;
155 }
156
157 if (output % 10 >= 5) {
158 output /= 10;
159 output += 1;
160 exp += 1;
161
162 // e.g. 9999 -> 10000
163 if (isPowerOf10(output)) {
164 output /= 10;
165 exp += 1;
166 }
167 }
168 }
169
170 return .{
171 .mantissa = output,
172 .exponent = exp,
173 .sign = f.sign,
174 };
175}
176
177/// Write a FloatDecimal128 to a buffer in scientific form.
178///
179/// The buffer provided must be greater than `min_buffer_size` in length. If no precision is
180/// specified, this function will never return an error. If a precision is specified, up to
181/// `8 + precision` bytes will be written to the buffer. An error will be returned if the content
182/// will not fit.
183///
184/// It is recommended to bound decimal formatting with an exact precision.
185pub fn formatScientific(buf: []u8, f_: FloatDecimal128, precision: ?usize) FormatError![]const u8 {
186 std.debug.assert(buf.len >= min_buffer_size);
187 var f = f_;
188
189 if (f.exponent == special_exponent) {
190 return copySpecialStr(buf, f);
191 }
192
193 if (precision) |prec| {
194 f = round(f, .scientific, prec);
195 }
196
197 var output = f.mantissa;
198 const olength = decimalLength(output);
199
200 if (precision) |prec| {
201 // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4)
202 const req_bytes = 8 + prec;
203 if (buf.len < req_bytes) {
204 return error.BufferTooSmall;
205 }
206 }
207
208 // Step 5: Print the scientific representation
209 var index: usize = 0;
210 if (f.sign) {
211 buf[index] = '-';
212 index += 1;
213 }
214
215 // 1.12345
216 writeDecimal(buf[index + 2 ..], &output, olength - 1);
217 buf[index] = '0' + @as(u8, @intCast(output % 10));
218 buf[index + 1] = '.';
219 index += 2;
220 const dp_index = index;
221 if (olength > 1) index += olength - 1 else index -= 1;
222
223 if (precision) |prec| {
224 index += @intFromBool(olength == 1);
225 if (prec > olength - 1) {
226 const len = prec - (olength - 1);
227 @memset(buf[index..][0..len], '0');
228 index += len;
229 } else {
230 index = dp_index + prec - @intFromBool(prec == 0);
231 }
232 }
233
234 // e100
235 buf[index] = 'e';
236 index += 1;
237 var exp = f.exponent + @as(i32, @intCast(olength)) - 1;
238 if (exp < 0) {
239 buf[index] = '-';
240 index += 1;
241 exp = -exp;
242 }
243 var uexp: u32 = @intCast(exp);
244 const elength = decimalLength(uexp);
245 writeDecimal(buf[index..], &uexp, elength);
246 index += elength;
247
248 return buf[0..index];
249}
250
251/// Write a FloatDecimal128 to a buffer in decimal form.
252///
253/// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is
254/// specified, this may still return an error. If precision is specified, `2 + precision` bytes will
255/// always be written.
256pub fn formatDecimal(buf: []u8, f_: FloatDecimal128, precision: ?usize) FormatError![]const u8 {
257 std.debug.assert(buf.len >= min_buffer_size);
258 var f = f_;
259
260 if (f.exponent == special_exponent) {
261 return copySpecialStr(buf, f);
262 }
263
264 if (precision) |prec| {
265 f = round(f, .decimal, prec);
266 }
267
268 var output = f.mantissa;
269 const olength = decimalLength(output);
270
271 // fixed bound: leading_digit(1) + point(1)
272 const req_bytes = if (f.exponent >= 0)
273 2 + @abs(f.exponent) + olength + (precision orelse 0)
274 else
275 2 + @max(@abs(f.exponent) + olength, precision orelse 0);
276 if (buf.len < req_bytes) {
277 return error.BufferTooSmall;
278 }
279
280 // Step 5: Print the decimal representation
281 var index: usize = 0;
282 if (f.sign) {
283 buf[index] = '-';
284 index += 1;
285 }
286
287 const dp_offset = f.exponent + cast_i32(olength);
288 if (dp_offset <= 0) {
289 // 0.000001234
290 buf[index] = '0';
291 buf[index + 1] = '.';
292 index += 2;
293 const dp_index = index;
294
295 const dp_poffset: u32 = @intCast(-dp_offset);
296 @memset(buf[index..][0..dp_poffset], '0');
297 index += dp_poffset;
298 writeDecimal(buf[index..], &output, olength);
299 index += olength;
300
301 if (precision) |prec| {
302 const dp_written = index - dp_index;
303 if (prec > dp_written) {
304 @memset(buf[index..][0 .. prec - dp_written], '0');
305 }
306 index = dp_index + prec - @intFromBool(prec == 0);
307 }
308 } else {
309 // 123456000
310 const dp_uoffset: usize = @intCast(dp_offset);
311 if (dp_uoffset >= olength) {
312 writeDecimal(buf[index..], &output, olength);
313 index += olength;
314 @memset(buf[index..][0 .. dp_uoffset - olength], '0');
315 index += dp_uoffset - olength;
316
317 if (precision) |prec| {
318 if (prec != 0) {
319 buf[index] = '.';
320 index += 1;
321 @memset(buf[index..][0..prec], '0');
322 index += prec;
323 }
324 }
325 } else {
326 // 12345.6789
327 writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset);
328 buf[index + dp_uoffset] = '.';
329 const dp_index = index + dp_uoffset + 1;
330 writeDecimal(buf[index..], &output, dp_uoffset);
331 index += olength + 1;
332
333 if (precision) |prec| {
334 const dp_written = olength - dp_uoffset;
335 if (prec > dp_written) {
336 @memset(buf[index..][0 .. prec - dp_written], '0');
337 }
338 index = dp_index + prec - @intFromBool(prec == 0);
339 }
340 }
341 }
342
343 return buf[0..index];
344}
345
346fn cast_i32(v: anytype) i32 {
347 return @intCast(v);
348}
349
350/// Convert a binary float representation to decimal.
351pub fn binaryToDecimal(bits: u128, mantissa_bits: u7, exponent_bits: u5, explicit_leading_bit: bool) FloatDecimal128 {
352 const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
353 const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
354 const ieee_mantissa = bits & ((@as(u128, 1) << mantissa_bits) - 1);
355 const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(u128, 1) << exponent_bits) - 1));
356
357 if (ieee_exponent == 0 and ieee_mantissa == 0) {
358 return .{
359 .mantissa = 0,
360 .exponent = 0,
361 .sign = ieee_sign,
362 };
363 }
364 if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
365 return .{
366 .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(u128, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
367 .exponent = 0x7fffffff,
368 .sign = ieee_sign,
369 };
370 }
371
372 var e2: i32 = undefined;
373 var m2: u128 = undefined;
374 if (explicit_leading_bit) {
375 if (ieee_exponent == 0) {
376 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
377 } else {
378 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
379 }
380 m2 = ieee_mantissa;
381 } else {
382 if (ieee_exponent == 0) {
383 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
384 m2 = ieee_mantissa;
385 } else {
386 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
387 m2 = (@as(u128, 1) << mantissa_bits) | ieee_mantissa;
388 }
389 }
390 const even = (m2 & 1) == 0;
391 const accept_bounds = even;
392
393 // Step 2: Determine the interval of legal decimal representations.
394 const mv = 4 * m2;
395 const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(u128, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));
396
397 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
398 var vr: u128 = undefined;
399 var vp: u128 = undefined;
400 var vm: u128 = undefined;
401 var e10: i32 = undefined;
402 var vm_is_trailing_zeros = false;
403 var vr_is_trailing_zeros = false;
404 if (e2 >= 0) {
405 const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
406 e10 = cast_i32(q);
407 const k: i32 = @intCast(FLOAT_128_POW5_INV_BITCOUNT + pow5Bits(q) - 1);
408 const i: u32 = @intCast(-e2 + cast_i32(q) + k);
409
410 const pow5 = computeInvPow5(q);
411 vr = mulShift(4 * m2, &pow5, i);
412 vp = mulShift(4 * m2 + 2, &pow5, i);
413 vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, i);
414
415 if (q <= 55) {
416 if (mv % 5 == 0) {
417 vr_is_trailing_zeros = multipleOfPowerOf5(mv, q -% 1);
418 } else if (accept_bounds) {
419 vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
420 } else {
421 vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
422 }
423 }
424 } else {
425 const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
426 e10 = cast_i32(q) + e2;
427 const i: i32 = -e2 - cast_i32(q);
428 const k: i32 = cast_i32(pow5Bits(@intCast(i))) - FLOAT_128_POW5_BITCOUNT;
429 const j: u32 = @intCast(cast_i32(q) - k);
430
431 const pow5 = computePow5(@intCast(i));
432 vr = mulShift(4 * m2, &pow5, j);
433 vp = mulShift(4 * m2 + 2, &pow5, j);
434 vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, j);
435
436 if (q <= 1) {
437 vr_is_trailing_zeros = true;
438 if (accept_bounds) {
439 vm_is_trailing_zeros = mm_shift == 1;
440 } else {
441 vp -= 1;
442 }
443 } else if (q < 127) {
444 vr_is_trailing_zeros = multipleOfPowerOf2(mv, q - 1);
445 }
446 }
447
448 // Step 4: Find the shortest decimal representation in the interval of legal representations.
449 var removed: u32 = 0;
450 var last_removed_digit: u8 = 0;
451
452 while (vp / 10 > vm / 10) {
453 vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
454 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
455 last_removed_digit = @intCast(vr % 10);
456 vr /= 10;
457 vp /= 10;
458 vm /= 10;
459 removed += 1;
460 }
461
462 if (vm_is_trailing_zeros) {
463 while (vm % 10 == 0) {
464 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
465 last_removed_digit = @intCast(vr % 10);
466 vr /= 10;
467 vp /= 10;
468 vm /= 10;
469 removed += 1;
470 }
471 }
472
473 if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
474 last_removed_digit = 4;
475 }
476
477 return .{
478 .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
479 .exponent = e10 + cast_i32(removed),
480 .sign = ieee_sign,
481 };
482}
483
484fn decimalLength(v: u128) u32 {
485 const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280;
486 var p10 = LARGEST_POW10;
487 var i: u32 = 39;
488 while (i > 0) : (i -= 1) {
489 if (v >= p10) return i;
490 p10 /= 10;
491 }
492 return 1;
493}
494
495// floor(log_10(2^e))
496fn log10Pow2(e: u32) u32 {
497 std.debug.assert(e <= 1 << 15);
498 return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49);
499}
500
501// floor(log_10(5^e))
502fn log10Pow5(e: u32) u32 {
503 std.debug.assert(e <= 1 << 15);
504 return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48);
505}
506
507// if (e == 0) 1 else ceil(log_2(5^e))
508fn pow5Bits(e: u32) u32 {
509 std.debug.assert(e <= 1 << 15);
510 return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1);
511}
512
513fn pow5Factor(value_: u128) u32 {
514 var count: u32 = 0;
515 var value = value_;
516 while (value > 0) : ({
517 count += 1;
518 value /= 5;
519 }) {
520 if (value % 5 != 0) return count;
521 }
522 return 0;
523}
524
525fn multipleOfPowerOf5(value: u128, p: u32) bool {
526 return pow5Factor(value) >= p;
527}
528
529fn multipleOfPowerOf2(value: u128, p: u32) bool {
530 return (value & ((@as(u128, 1) << @as(u7, @intCast(p))) - 1)) == 0;
531}
532
533fn computeInvPow5(i: u32) [4]u64 {
534 const base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE;
535 const base2 = base * POW5_TABLE_SIZE;
536 const mul = &GENERIC_POW5_INV_SPLIT[base]; // 1 / 5^base2
537 if (i == base2) {
538 return .{ mul[0] + 1, mul[1], mul[2], mul[3] };
539 } else {
540 const offset = base2 - i;
541 const m = &GENERIC_POW5_TABLE[offset]; // 5^offset
542 const delta = pow5Bits(base2) - pow5Bits(i);
543
544 const shift: u6 = @intCast(2 * (i % 32));
545 const corr: u32 = @intCast(((POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1);
546 return mul_128_256_shift(m, mul, delta, corr);
547 }
548}
549
550fn computePow5(i: u32) [4]u64 {
551 const base = i / POW5_TABLE_SIZE;
552 const base2 = base * POW5_TABLE_SIZE;
553 const mul = &GENERIC_POW5_SPLIT[base];
554 if (i == base2) {
555 return mul.*;
556 } else {
557 const offset = i - base2;
558 const m = &GENERIC_POW5_TABLE[offset];
559 const delta = pow5Bits(i) - pow5Bits(base2);
560
561 const shift: u6 = @intCast(2 * (i % 32));
562 const corr: u32 = @intCast((POW5_ERRORS[i / 32] >> shift) & 3);
563 return mul_128_256_shift(m, mul, delta, corr);
564 }
565}
566
567fn mulShift(m: u128, mul: *const [4]u64, j: u32) u128 {
568 std.debug.assert(j > 128);
569 const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) };
570 const r = mul_128_256_shift(&a, mul, j, 0);
571 return (@as(u128, r[1]) << 64) | r[0];
572}
573
574fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 {
575 std.debug.assert(shift > 0);
576 std.debug.assert(shift < 256);
577
578 const b00 = @as(u128, a[0]) * b[0];
579 const b01 = @as(u128, a[0]) * b[1];
580 const b02 = @as(u128, a[0]) * b[2];
581 const b03 = @as(u128, a[0]) * b[3];
582 const b10 = @as(u128, a[1]) * b[0];
583 const b11 = @as(u128, a[1]) * b[1];
584 const b12 = @as(u128, a[1]) * b[2];
585 const b13 = @as(u128, a[1]) * b[3];
586
587 const s0 = b00;
588 const s1 = b01 +% b10;
589 const c1: u128 = @intFromBool(s1 < b01);
590 const s2 = b02 +% b11;
591 const c2: u128 = @intFromBool(s2 < b02);
592 const s3 = b03 +% b12;
593 const c3: u128 = @intFromBool(s3 < b03);
594
595 const p0 = s0 +% (s1 << 64);
596 const d0: u128 = @intFromBool(p0 < b00);
597 const q1 = s2 +% (s1 >> 64) +% (s3 << 64);
598 const d1: u128 = @intFromBool(q1 < s2);
599 const p1 = q1 +% (c1 << 64) +% d0;
600 const d2: u128 = @intFromBool(p1 < q1);
601 const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2;
602
603 var r0: u128 = undefined;
604 var r1: u128 = undefined;
605 if (shift < 128) {
606 const cshift: u7 = @intCast(shift);
607 const sshift: u7 = @intCast(128 - shift);
608 r0 = corr +% ((p0 >> cshift) | (p1 << sshift));
609 r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr);
610 } else if (shift == 128) {
611 r0 = corr +% p1;
612 r1 = p2 +% @intFromBool(r0 < corr);
613 } else {
614 const ashift: u7 = @intCast(shift - 128);
615 const sshift: u7 = @intCast(256 - shift);
616 r0 = corr +% ((p1 >> ashift) | (p2 << sshift));
617 r1 = (p2 >> ashift) +% @intFromBool(r0 < corr);
618 }
619
620 return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) };
621}
622
623// zig fmt: off
624//
625// 4.5KiB of tables.
626
627const FLOAT_128_POW5_INV_BITCOUNT = 249;
628const FLOAT_128_POW5_BITCOUNT = 249;
629const POW5_TABLE_SIZE = 56;
630
631const GENERIC_POW5_TABLE: [POW5_TABLE_SIZE][2]u64 = .{
632 .{ 1, 0 },
633 .{ 5, 0 },
634 .{ 25, 0 },
635 .{ 125, 0 },
636 .{ 625, 0 },
637 .{ 3125, 0 },
638 .{ 15625, 0 },
639 .{ 78125, 0 },
640 .{ 390625, 0 },
641 .{ 1953125, 0 },
642 .{ 9765625, 0 },
643 .{ 48828125, 0 },
644 .{ 244140625, 0 },
645 .{ 1220703125, 0 },
646 .{ 6103515625, 0 },
647 .{ 30517578125, 0 },
648 .{ 152587890625, 0 },
649 .{ 762939453125, 0 },
650 .{ 3814697265625, 0 },
651 .{ 19073486328125, 0 },
652 .{ 95367431640625, 0 },
653 .{ 476837158203125, 0 },
654 .{ 2384185791015625, 0 },
655 .{ 11920928955078125, 0 },
656 .{ 59604644775390625, 0 },
657 .{ 298023223876953125, 0 },
658 .{ 1490116119384765625, 0 },
659 .{ 7450580596923828125, 0 },
660 .{ 359414837200037393, 2 },
661 .{ 1797074186000186965, 10 },
662 .{ 8985370930000934825, 50 },
663 .{ 8033366502585570893, 252 },
664 .{ 3273344365508751233, 1262 },
665 .{ 16366721827543756165, 6310 },
666 .{ 8046632842880574361, 31554 },
667 .{ 3339676066983768573, 157772 },
668 .{ 16698380334918842865, 788860 },
669 .{ 9704925379756007861, 3944304 },
670 .{ 11631138751360936073, 19721522 },
671 .{ 2815461535676025517, 98607613 },
672 .{ 14077307678380127585, 493038065 },
673 .{ 15046306170771983077, 2465190328 },
674 .{ 1444554559021708921, 12325951644 },
675 .{ 7222772795108544605, 61629758220 },
676 .{ 17667119901833171409, 308148791101 },
677 .{ 14548623214327650581, 1540743955509 },
678 .{ 17402883850509598057, 7703719777548 },
679 .{ 13227442957709783821, 38518598887744 },
680 .{ 10796982567420264257, 192592994438723 },
681 .{ 17091424689682218053, 962964972193617 },
682 .{ 11670147153572883801, 4814824860968089 },
683 .{ 3010503546735764157, 24074124304840448 },
684 .{ 15052517733678820785, 120370621524202240 },
685 .{ 1475612373555897461, 601853107621011204 },
686 .{ 7378061867779487305, 3009265538105056020 },
687 .{ 18443565265187884909, 15046327690525280101 },
688};
689
690const GENERIC_POW5_SPLIT: [89][4]u64 = .{
691 .{ 0, 0, 0, 72057594037927936 },
692 .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 },
693 .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 },
694 .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 },
695 .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 },
696 .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 },
697 .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 },
698 .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 },
699 .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 },
700 .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 },
701 .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 },
702 .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 },
703 .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 },
704 .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 },
705 .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 },
706 .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 },
707 .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 },
708 .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 },
709 .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 },
710 .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 },
711 .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 },
712 .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 },
713 .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 },
714 .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 },
715 .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 },
716 .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 },
717 .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 },
718 .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 },
719 .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 },
720 .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 },
721 .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 },
722 .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 },
723 .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 },
724 .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 },
725 .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 },
726 .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 },
727 .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 },
728 .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 },
729 .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 },
730 .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 },
731 .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 },
732 .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 },
733 .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 },
734 .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 },
735 .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 },
736 .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 },
737 .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 },
738 .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 },
739 .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 },
740 .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 },
741 .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 },
742 .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 },
743 .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 },
744 .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 },
745 .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 },
746 .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 },
747 .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 },
748 .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 },
749 .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 },
750 .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 },
751 .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 },
752 .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 },
753 .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 },
754 .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 },
755 .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 },
756 .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 },
757 .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 },
758 .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 },
759 .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 },
760 .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 },
761 .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 },
762 .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 },
763 .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 },
764 .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 },
765 .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 },
766 .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 },
767 .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 },
768 .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 },
769 .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 },
770 .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 },
771 .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 },
772 .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 },
773 .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 },
774 .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 },
775 .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 },
776 .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 },
777 .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 },
778 .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 },
779 .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 },
780};
781
782// Unfortunately, the results are sometimes off by one or two. We use an additional
783// lookup table to store those cases and adjust the result.
784const POW5_ERRORS: [156]u64 = .{
785 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000,
786 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964,
787 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115,
788 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000,
789 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441,
790 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545,
791 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445,
792 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565,
793 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140,
794 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015,
795 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145,
796 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040,
797 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004,
798 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111,
799 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511,
800 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050,
801 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955,
802 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655,
803 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155,
804 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455,
805 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000,
806 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564,
807 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644,
808 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255,
809 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005,
810 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010,
811 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000,
812 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004,
813 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411,
814 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000,
815 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015,
816 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965,
817 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555,
818 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000,
819 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411,
820 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555,
821 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514,
822 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550,
823 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000,
824};
825
826const GENERIC_POW5_INV_SPLIT: [89][4]u64 = .{
827 .{ 0, 0, 0, 144115188075855872 },
828 .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 },
829 .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 },
830 .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 },
831 .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 },
832 .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 },
833 .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 },
834 .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 },
835 .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 },
836 .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 },
837 .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 },
838 .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 },
839 .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 },
840 .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 },
841 .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 },
842 .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 },
843 .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 },
844 .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 },
845 .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 },
846 .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 },
847 .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 },
848 .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 },
849 .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 },
850 .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 },
851 .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 },
852 .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 },
853 .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 },
854 .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 },
855 .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 },
856 .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 },
857 .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 },
858 .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 },
859 .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 },
860 .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 },
861 .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 },
862 .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 },
863 .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 },
864 .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 },
865 .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 },
866 .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 },
867 .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 },
868 .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 },
869 .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 },
870 .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 },
871 .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 },
872 .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 },
873 .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 },
874 .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 },
875 .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 },
876 .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 },
877 .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 },
878 .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 },
879 .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 },
880 .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 },
881 .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 },
882 .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 },
883 .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 },
884 .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 },
885 .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 },
886 .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 },
887 .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 },
888 .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 },
889 .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 },
890 .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 },
891 .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 },
892 .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 },
893 .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 },
894 .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 },
895 .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 },
896 .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 },
897 .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 },
898 .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 },
899 .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 },
900 .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 },
901 .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 },
902 .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 },
903 .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 },
904 .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 },
905 .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 },
906 .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 },
907 .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 },
908 .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 },
909 .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 },
910 .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 },
911 .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 },
912 .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 },
913 .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 },
914 .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 },
915 .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 },
916};
917
918const POW5_INV_ERRORS: [154]u64 = .{
919 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000,
920 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014,
921 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105,
922 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110,
923 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558,
924 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010,
925 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400,
926 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055,
927 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000,
928 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444,
929 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000,
930 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555,
931 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155,
932 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511,
933 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559,
934 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540,
935 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151,
936 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000,
937 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000,
938 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155,
939 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000,
940 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545,
941 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050,
942 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401,
943 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505,
944 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545,
945 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141,
946 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510,
947 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559,
948 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514,
949 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410,
950 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541,
951 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500,
952 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445,
953 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414,
954 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500,
955 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040,
956 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455,
957 0x0040000400105555, 0x0000000000000001,
958};
959
960// zig fmt: on
961
962fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
963 const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
964
965 var buf: [6000]u8 = undefined;
966 const value_bits: I = @bitCast(value);
967 const s = try formatFloat(&buf, value, .{});
968 try std.testing.expectEqualStrings(expected, s);
969
970 if (@bitSizeOf(T) != 80) {
971 const o = try std.fmt.parseFloat(T, s);
972 const o_bits: I = @bitCast(o);
973
974 if (std.math.isNan(value)) {
975 try std.testing.expect(std.math.isNan(o));
976 } else {
977 try std.testing.expectEqual(value_bits, o_bits);
978 }
979 }
980}
981
982test "format f32" {
983 try check(f32, 0.0, "0e0");
984 try check(f32, -0.0, "-0e0");
985 try check(f32, 1.0, "1e0");
986 try check(f32, -1.0, "-1e0");
987 try check(f32, std.math.nan(f32), "nan");
988 try check(f32, std.math.inf(f32), "inf");
989 try check(f32, -std.math.inf(f32), "-inf");
990 try check(f32, 1.1754944e-38, "1.1754944e-38");
991 try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38");
992 try check(f32, @bitCast(@as(u32, 1)), "1e-45");
993 try check(f32, 3.355445E7, "3.355445e7");
994 try check(f32, 8.999999e9, "9e9");
995 try check(f32, 3.4366717e10, "3.436672e10");
996 try check(f32, 3.0540412e5, "3.0540412e5");
997 try check(f32, 8.0990312e3, "8.0990312e3");
998 try check(f32, 2.4414062e-4, "2.4414062e-4");
999 try check(f32, 2.4414062e-3, "2.4414062e-3");
1000 try check(f32, 4.3945312e-3, "4.3945312e-3");
1001 try check(f32, 6.3476562e-3, "6.3476562e-3");
1002 try check(f32, 4.7223665e21, "4.7223665e21");
1003 try check(f32, 8388608.0, "8.388608e6");
1004 try check(f32, 1.6777216e7, "1.6777216e7");
1005 try check(f32, 3.3554436e7, "3.3554436e7");
1006 try check(f32, 6.7131496e7, "6.7131496e7");
1007 try check(f32, 1.9310392e-38, "1.9310392e-38");
1008 try check(f32, -2.47e-43, "-2.47e-43");
1009 try check(f32, 1.993244e-38, "1.993244e-38");
1010 try check(f32, 4103.9003, "4.1039004e3");
1011 try check(f32, 5.3399997e9, "5.3399997e9");
1012 try check(f32, 6.0898e-39, "6.0898e-39");
1013 try check(f32, 0.0010310042, "1.0310042e-3");
1014 try check(f32, 2.8823261e17, "2.882326e17");
1015 try check(f32, 7.038531e-26, "7.038531e-26");
1016 try check(f32, 9.2234038e17, "9.223404e17");
1017 try check(f32, 6.7108872e7, "6.710887e7");
1018 try check(f32, 1.0e-44, "1e-44");
1019 try check(f32, 2.816025e14, "2.816025e14");
1020 try check(f32, 9.223372e18, "9.223372e18");
1021 try check(f32, 1.5846085e29, "1.5846086e29");
1022 try check(f32, 1.1811161e19, "1.1811161e19");
1023 try check(f32, 5.368709e18, "5.368709e18");
1024 try check(f32, 4.6143165e18, "4.6143166e18");
1025 try check(f32, 0.007812537, "7.812537e-3");
1026 try check(f32, 1.4e-45, "1e-45");
1027 try check(f32, 1.18697724e20, "1.18697725e20");
1028 try check(f32, 1.00014165e-36, "1.00014165e-36");
1029 try check(f32, 200.0, "2e2");
1030 try check(f32, 3.3554432e7, "3.3554432e7");
1031
1032 try check(f32, 1.0, "1e0");
1033 try check(f32, 1.2, "1.2e0");
1034 try check(f32, 1.23, "1.23e0");
1035 try check(f32, 1.234, "1.234e0");
1036 try check(f32, 1.2345, "1.2345e0");
1037 try check(f32, 1.23456, "1.23456e0");
1038 try check(f32, 1.234567, "1.234567e0");
1039 try check(f32, 1.2345678, "1.2345678e0");
1040 try check(f32, 1.23456735e-36, "1.23456735e-36");
1041}
1042
1043test "format f64" {
1044 try check(f64, 0.0, "0e0");
1045 try check(f64, -0.0, "-0e0");
1046 try check(f64, 1.0, "1e0");
1047 try check(f64, -1.0, "-1e0");
1048 try check(f64, std.math.nan(f64), "nan");
1049 try check(f64, std.math.inf(f64), "inf");
1050 try check(f64, -std.math.inf(f64), "-inf");
1051 try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308");
1052 try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308");
1053 try check(f64, @bitCast(@as(u64, 1)), "5e-324");
1054 try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8");
1055 try check(f64, -2.109808898695963e16, "-2.109808898695963e16");
1056 try check(f64, 4.940656e-318, "4.940656e-318");
1057 try check(f64, 1.18575755e-316, "1.18575755e-316");
1058 try check(f64, 2.989102097996e-312, "2.989102097996e-312");
1059 try check(f64, 9.0608011534336e15, "9.0608011534336e15");
1060 try check(f64, 4.708356024711512e18, "4.708356024711512e18");
1061 try check(f64, 9.409340012568248e18, "9.409340012568248e18");
1062 try check(f64, 1.2345678, "1.2345678e0");
1063 try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39");
1064 try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40");
1065 try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40");
1066
1067 try check(f64, 1, "1e0");
1068 try check(f64, 1.2, "1.2e0");
1069 try check(f64, 1.23, "1.23e0");
1070 try check(f64, 1.234, "1.234e0");
1071 try check(f64, 1.2345, "1.2345e0");
1072 try check(f64, 1.23456, "1.23456e0");
1073 try check(f64, 1.234567, "1.234567e0");
1074 try check(f64, 1.2345678, "1.2345678e0");
1075 try check(f64, 1.23456789, "1.23456789e0");
1076 try check(f64, 1.234567895, "1.234567895e0");
1077 try check(f64, 1.2345678901, "1.2345678901e0");
1078 try check(f64, 1.23456789012, "1.23456789012e0");
1079 try check(f64, 1.234567890123, "1.234567890123e0");
1080 try check(f64, 1.2345678901234, "1.2345678901234e0");
1081 try check(f64, 1.23456789012345, "1.23456789012345e0");
1082 try check(f64, 1.234567890123456, "1.234567890123456e0");
1083 try check(f64, 1.2345678901234567, "1.2345678901234567e0");
1084
1085 try check(f64, 4.294967294, "4.294967294e0");
1086 try check(f64, 4.294967295, "4.294967295e0");
1087 try check(f64, 4.294967296, "4.294967296e0");
1088 try check(f64, 4.294967297, "4.294967297e0");
1089 try check(f64, 4.294967298, "4.294967298e0");
1090}
1091
1092test "format f80" {
1093 try check(f80, 0.0, "0e0");
1094 try check(f80, -0.0, "-0e0");
1095 try check(f80, 1.0, "1e0");
1096 try check(f80, -1.0, "-1e0");
1097 try check(f80, std.math.nan(f80), "nan");
1098 try check(f80, std.math.inf(f80), "inf");
1099 try check(f80, -std.math.inf(f80), "-inf");
1100
1101 try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308");
1102 try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8");
1103 try check(f80, -2.109808898695963e16, "-2.109808898695963e16");
1104 try check(f80, 4.940656e-318, "4.940656e-318");
1105 try check(f80, 1.18575755e-316, "1.18575755e-316");
1106 try check(f80, 2.989102097996e-312, "2.989102097996e-312");
1107 try check(f80, 9.0608011534336e15, "9.0608011534336e15");
1108 try check(f80, 4.708356024711512e18, "4.708356024711512e18");
1109 try check(f80, 9.409340012568248e18, "9.409340012568248e18");
1110 try check(f80, 1.2345678, "1.2345678e0");
1111}
1112
1113test "format f128" {
1114 try check(f128, 0.0, "0e0");
1115 try check(f128, -0.0, "-0e0");
1116 try check(f128, 1.0, "1e0");
1117 try check(f128, -1.0, "-1e0");
1118 try check(f128, std.math.nan(f128), "nan");
1119 try check(f128, std.math.inf(f128), "inf");
1120 try check(f128, -std.math.inf(f128), "-inf");
1121
1122 try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308");
1123 try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8");
1124 try check(f128, -2.109808898695963e16, "-2.109808898695963e16");
1125 try check(f128, 4.940656e-318, "4.940656e-318");
1126 try check(f128, 1.18575755e-316, "1.18575755e-316");
1127 try check(f128, 2.989102097996e-312, "2.989102097996e-312");
1128 try check(f128, 9.0608011534336e15, "9.0608011534336e15");
1129 try check(f128, 4.708356024711512e18, "4.708356024711512e18");
1130 try check(f128, 9.409340012568248e18, "9.409340012568248e18");
1131 try check(f128, 1.2345678, "1.2345678e0");
1132}
1133
1134test "format float to decimal with zero precision" {
1135 try expectFmt("5", "{d:.0}", .{5});
1136 try expectFmt("6", "{d:.0}", .{6});
1137 try expectFmt("7", "{d:.0}", .{7});
1138 try expectFmt("8", "{d:.0}", .{8});
1139}
lib/std/fmt/ryu128.zig deleted-1139
......@@ -1,1139 +0,0 @@
1//! This file implements the ryu floating point conversion algorithm:
2//! https://dl.acm.org/doi/pdf/10.1145/3360595
3
4const std = @import("std");
5const expectFmt = std.testing.expectFmt;
6
7const special_exponent = 0x7fffffff;
8
9/// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will
10/// additionally be performed if more bytes are required.
11pub const min_buffer_size = 53;
12
13/// Returns the minimum buffer size needed to print every float of a specific type and format.
14pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int {
15 comptime std.debug.assert(@typeInfo(T) == .Float);
16 return switch (mode) {
17 .scientific => 53,
18 // Based on minimum subnormal values.
19 .decimal => switch (@bitSizeOf(T)) {
20 16 => @max(15, min_buffer_size),
21 32 => 55,
22 64 => 347,
23 80 => 4996,
24 128 => 5011,
25 else => unreachable,
26 },
27 };
28}
29
30pub const RyuError = error{
31 BufferTooSmall,
32};
33
34pub const Format = enum {
35 scientific,
36 decimal,
37};
38
39pub const FormatOptions = struct {
40 mode: Format = .scientific,
41 precision: ?usize = null,
42};
43
44/// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing
45/// the string representation.
46///
47/// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat
48/// unambiguously.
49///
50/// Scientific mode is recommended generally as the output is more compact and any type can be
51/// written in full precision using a buffer of only `min_buffer_size`.
52///
53/// When printing full precision decimals, use `bufferSize` to get the required space. It is
54/// recommended to bound decimal output with a fixed precision to reduce the required buffer size.
55pub fn format(buf: []u8, v_: anytype, options: FormatOptions) RyuError![]const u8 {
56 const v = switch (@TypeOf(v_)) {
57 // comptime_float internally is a f128; this preserves precision.
58 comptime_float => @as(f128, v_),
59 else => v_,
60 };
61
62 const T = @TypeOf(v);
63 comptime std.debug.assert(@typeInfo(T) == .Float);
64 const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
65
66 const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0;
67 const d = binaryToDecimal(@as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit);
68
69 return switch (options.mode) {
70 .scientific => formatScientific(buf, d, options.precision),
71 .decimal => formatDecimal(buf, d, options.precision),
72 };
73}
74
75pub const FloatDecimal128 = struct {
76 mantissa: u128,
77 exponent: i32,
78 sign: bool,
79};
80
81fn copySpecialStr(buf: []u8, f: FloatDecimal128) []const u8 {
82 if (f.sign) {
83 buf[0] = '-';
84 }
85 const offset: usize = @intFromBool(f.sign);
86 if (f.mantissa != 0) {
87 @memcpy(buf[offset..][0..3], "nan");
88 return buf[0 .. 3 + offset];
89 }
90 @memcpy(buf[offset..][0..3], "inf");
91 return buf[0 .. 3 + offset];
92}
93
94fn writeDecimal(buf: []u8, value: anytype, count: usize) void {
95 var i: usize = 0;
96
97 while (i + 2 < count) : (i += 2) {
98 const c: u8 = @intCast(value.* % 100);
99 value.* /= 100;
100 const d = std.fmt.digits2(c);
101 buf[count - i - 1] = d[1];
102 buf[count - i - 2] = d[0];
103 }
104
105 while (i < count) : (i += 1) {
106 const c: u8 = @intCast(value.* % 10);
107 value.* /= 10;
108 buf[count - i - 1] = '0' + c;
109 }
110}
111
112fn isPowerOf10(n_: u128) bool {
113 var n = n_;
114 while (n != 0) : (n /= 10) {
115 if (n % 10 != 0) return false;
116 }
117 return true;
118}
119
120const RoundMode = enum {
121 /// 1234.56 = precision 2
122 decimal,
123 /// 1.23456e3 = precision 5
124 scientific,
125};
126
127fn round(f: FloatDecimal128, mode: RoundMode, precision: usize) FloatDecimal128 {
128 var round_digit: usize = 0;
129 var output = f.mantissa;
130 var exp = f.exponent;
131 const olength = decimalLength(output);
132
133 switch (mode) {
134 .decimal => {
135 if (f.exponent > 0) {
136 round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent));
137 } else {
138 const min_exp_required = @as(usize, @intCast(-f.exponent));
139 if (precision + olength > min_exp_required) {
140 round_digit = precision + olength - min_exp_required;
141 }
142 }
143 },
144 .scientific => {
145 round_digit = 1 + precision;
146 },
147 }
148
149 if (round_digit < olength) {
150 var nlength = olength;
151 for (round_digit + 1..olength) |_| {
152 output /= 10;
153 exp += 1;
154 nlength -= 1;
155 }
156
157 if (output % 10 >= 5) {
158 output /= 10;
159 output += 1;
160 exp += 1;
161
162 // e.g. 9999 -> 10000
163 if (isPowerOf10(output)) {
164 output /= 10;
165 exp += 1;
166 }
167 }
168 }
169
170 return .{
171 .mantissa = output,
172 .exponent = exp,
173 .sign = f.sign,
174 };
175}
176
177/// Write a FloatDecimal128 to a buffer in scientific form.
178///
179/// The buffer provided must be greater than `min_buffer_size` in length. If no precision is
180/// specified, this function will never return an error. If a precision is specified, up to
181/// `8 + precision` bytes will be written to the buffer. An error will be returned if the content
182/// will not fit.
183///
184/// It is recommended to bound decimal formatting with an exact precision.
185pub fn formatScientific(buf: []u8, f_: FloatDecimal128, precision: ?usize) RyuError![]const u8 {
186 std.debug.assert(buf.len >= min_buffer_size);
187 var f = f_;
188
189 if (f.exponent == special_exponent) {
190 return copySpecialStr(buf, f);
191 }
192
193 if (precision) |prec| {
194 f = round(f, .scientific, prec);
195 }
196
197 var output = f.mantissa;
198 const olength = decimalLength(output);
199
200 if (precision) |prec| {
201 // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4)
202 const req_bytes = 8 + prec;
203 if (buf.len < req_bytes) {
204 return error.BufferTooSmall;
205 }
206 }
207
208 // Step 5: Print the scientific representation
209 var index: usize = 0;
210 if (f.sign) {
211 buf[index] = '-';
212 index += 1;
213 }
214
215 // 1.12345
216 writeDecimal(buf[index + 2 ..], &output, olength - 1);
217 buf[index] = '0' + @as(u8, @intCast(output % 10));
218 buf[index + 1] = '.';
219 index += 2;
220 const dp_index = index;
221 if (olength > 1) index += olength - 1 else index -= 1;
222
223 if (precision) |prec| {
224 index += @intFromBool(olength == 1);
225 if (prec > olength - 1) {
226 const len = prec - (olength - 1);
227 @memset(buf[index..][0..len], '0');
228 index += len;
229 } else {
230 index = dp_index + prec - @intFromBool(prec == 0);
231 }
232 }
233
234 // e100
235 buf[index] = 'e';
236 index += 1;
237 var exp = f.exponent + @as(i32, @intCast(olength)) - 1;
238 if (exp < 0) {
239 buf[index] = '-';
240 index += 1;
241 exp = -exp;
242 }
243 var uexp: u32 = @intCast(exp);
244 const elength = decimalLength(uexp);
245 writeDecimal(buf[index..], &uexp, elength);
246 index += elength;
247
248 return buf[0..index];
249}
250
251/// Write a FloatDecimal128 to a buffer in decimal form.
252///
253/// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is
254/// specified, this may still return an error. If precision is specified, `2 + precision` bytes will
255/// always be written.
256pub fn formatDecimal(buf: []u8, f_: FloatDecimal128, precision: ?usize) RyuError![]const u8 {
257 std.debug.assert(buf.len >= min_buffer_size);
258 var f = f_;
259
260 if (f.exponent == special_exponent) {
261 return copySpecialStr(buf, f);
262 }
263
264 if (precision) |prec| {
265 f = round(f, .decimal, prec);
266 }
267
268 var output = f.mantissa;
269 const olength = decimalLength(output);
270
271 // fixed bound: leading_digit(1) + point(1)
272 const req_bytes = if (f.exponent >= 0)
273 2 + @abs(f.exponent) + olength + (precision orelse 0)
274 else
275 2 + @max(@abs(f.exponent) + olength, precision orelse 0);
276 if (buf.len < req_bytes) {
277 return error.BufferTooSmall;
278 }
279
280 // Step 5: Print the decimal representation
281 var index: usize = 0;
282 if (f.sign) {
283 buf[index] = '-';
284 index += 1;
285 }
286
287 const dp_offset = f.exponent + cast_i32(olength);
288 if (dp_offset <= 0) {
289 // 0.000001234
290 buf[index] = '0';
291 buf[index + 1] = '.';
292 index += 2;
293 const dp_index = index;
294
295 const dp_poffset: u32 = @intCast(-dp_offset);
296 @memset(buf[index..][0..dp_poffset], '0');
297 index += dp_poffset;
298 writeDecimal(buf[index..], &output, olength);
299 index += olength;
300
301 if (precision) |prec| {
302 const dp_written = index - dp_index;
303 if (prec > dp_written) {
304 @memset(buf[index..][0 .. prec - dp_written], '0');
305 }
306 index = dp_index + prec - @intFromBool(prec == 0);
307 }
308 } else {
309 // 123456000
310 const dp_uoffset: usize = @intCast(dp_offset);
311 if (dp_uoffset >= olength) {
312 writeDecimal(buf[index..], &output, olength);
313 index += olength;
314 @memset(buf[index..][0 .. dp_uoffset - olength], '0');
315 index += dp_uoffset - olength;
316
317 if (precision) |prec| {
318 if (prec != 0) {
319 buf[index] = '.';
320 index += 1;
321 @memset(buf[index..][0..prec], '0');
322 index += prec;
323 }
324 }
325 } else {
326 // 12345.6789
327 writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset);
328 buf[index + dp_uoffset] = '.';
329 const dp_index = index + dp_uoffset + 1;
330 writeDecimal(buf[index..], &output, dp_uoffset);
331 index += olength + 1;
332
333 if (precision) |prec| {
334 const dp_written = olength - dp_uoffset;
335 if (prec > dp_written) {
336 @memset(buf[index..][0 .. prec - dp_written], '0');
337 }
338 index = dp_index + prec - @intFromBool(prec == 0);
339 }
340 }
341 }
342
343 return buf[0..index];
344}
345
346fn cast_i32(v: anytype) i32 {
347 return @intCast(v);
348}
349
350/// Convert a binary float representation to decimal.
351pub fn binaryToDecimal(bits: u128, mantissa_bits: u7, exponent_bits: u5, explicit_leading_bit: bool) FloatDecimal128 {
352 const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
353 const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
354 const ieee_mantissa = bits & ((@as(u128, 1) << mantissa_bits) - 1);
355 const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(u128, 1) << exponent_bits) - 1));
356
357 if (ieee_exponent == 0 and ieee_mantissa == 0) {
358 return .{
359 .mantissa = 0,
360 .exponent = 0,
361 .sign = ieee_sign,
362 };
363 }
364 if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
365 return .{
366 .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(u128, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
367 .exponent = 0x7fffffff,
368 .sign = ieee_sign,
369 };
370 }
371
372 var e2: i32 = undefined;
373 var m2: u128 = undefined;
374 if (explicit_leading_bit) {
375 if (ieee_exponent == 0) {
376 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
377 } else {
378 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
379 }
380 m2 = ieee_mantissa;
381 } else {
382 if (ieee_exponent == 0) {
383 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
384 m2 = ieee_mantissa;
385 } else {
386 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
387 m2 = (@as(u128, 1) << mantissa_bits) | ieee_mantissa;
388 }
389 }
390 const even = (m2 & 1) == 0;
391 const accept_bounds = even;
392
393 // Step 2: Determine the interval of legal decimal representations.
394 const mv = 4 * m2;
395 const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(u128, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));
396
397 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
398 var vr: u128 = undefined;
399 var vp: u128 = undefined;
400 var vm: u128 = undefined;
401 var e10: i32 = undefined;
402 var vm_is_trailing_zeros = false;
403 var vr_is_trailing_zeros = false;
404 if (e2 >= 0) {
405 const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
406 e10 = cast_i32(q);
407 const k: i32 = @intCast(FLOAT_128_POW5_INV_BITCOUNT + pow5Bits(q) - 1);
408 const i: u32 = @intCast(-e2 + cast_i32(q) + k);
409
410 const pow5 = computeInvPow5(q);
411 vr = mulShift(4 * m2, &pow5, i);
412 vp = mulShift(4 * m2 + 2, &pow5, i);
413 vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, i);
414
415 if (q <= 55) {
416 if (mv % 5 == 0) {
417 vr_is_trailing_zeros = multipleOfPowerOf5(mv, q -% 1);
418 } else if (accept_bounds) {
419 vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
420 } else {
421 vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
422 }
423 }
424 } else {
425 const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
426 e10 = cast_i32(q) + e2;
427 const i: i32 = -e2 - cast_i32(q);
428 const k: i32 = cast_i32(pow5Bits(@intCast(i))) - FLOAT_128_POW5_BITCOUNT;
429 const j: u32 = @intCast(cast_i32(q) - k);
430
431 const pow5 = computePow5(@intCast(i));
432 vr = mulShift(4 * m2, &pow5, j);
433 vp = mulShift(4 * m2 + 2, &pow5, j);
434 vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, j);
435
436 if (q <= 1) {
437 vr_is_trailing_zeros = true;
438 if (accept_bounds) {
439 vm_is_trailing_zeros = mm_shift == 1;
440 } else {
441 vp -= 1;
442 }
443 } else if (q < 127) {
444 vr_is_trailing_zeros = multipleOfPowerOf2(mv, q - 1);
445 }
446 }
447
448 // Step 4: Find the shortest decimal representation in the interval of legal representations.
449 var removed: u32 = 0;
450 var last_removed_digit: u8 = 0;
451
452 while (vp / 10 > vm / 10) {
453 vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
454 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
455 last_removed_digit = @intCast(vr % 10);
456 vr /= 10;
457 vp /= 10;
458 vm /= 10;
459 removed += 1;
460 }
461
462 if (vm_is_trailing_zeros) {
463 while (vm % 10 == 0) {
464 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
465 last_removed_digit = @intCast(vr % 10);
466 vr /= 10;
467 vp /= 10;
468 vm /= 10;
469 removed += 1;
470 }
471 }
472
473 if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
474 last_removed_digit = 4;
475 }
476
477 return .{
478 .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
479 .exponent = e10 + cast_i32(removed),
480 .sign = ieee_sign,
481 };
482}
483
484fn decimalLength(v: u128) u32 {
485 const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280;
486 var p10 = LARGEST_POW10;
487 var i: u32 = 39;
488 while (i > 0) : (i -= 1) {
489 if (v >= p10) return i;
490 p10 /= 10;
491 }
492 return 1;
493}
494
495// floor(log_10(2^e))
496fn log10Pow2(e: u32) u32 {
497 std.debug.assert(e <= 1 << 15);
498 return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49);
499}
500
501// floor(log_10(5^e))
502fn log10Pow5(e: u32) u32 {
503 std.debug.assert(e <= 1 << 15);
504 return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48);
505}
506
507// if (e == 0) 1 else ceil(log_2(5^e))
508fn pow5Bits(e: u32) u32 {
509 std.debug.assert(e <= 1 << 15);
510 return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1);
511}
512
513fn pow5Factor(value_: u128) u32 {
514 var count: u32 = 0;
515 var value = value_;
516 while (value > 0) : ({
517 count += 1;
518 value /= 5;
519 }) {
520 if (value % 5 != 0) return count;
521 }
522 return 0;
523}
524
525fn multipleOfPowerOf5(value: u128, p: u32) bool {
526 return pow5Factor(value) >= p;
527}
528
529fn multipleOfPowerOf2(value: u128, p: u32) bool {
530 return (value & ((@as(u128, 1) << @as(u7, @intCast(p))) - 1)) == 0;
531}
532
533fn computeInvPow5(i: u32) [4]u64 {
534 const base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE;
535 const base2 = base * POW5_TABLE_SIZE;
536 const mul = &GENERIC_POW5_INV_SPLIT[base]; // 1 / 5^base2
537 if (i == base2) {
538 return .{ mul[0] + 1, mul[1], mul[2], mul[3] };
539 } else {
540 const offset = base2 - i;
541 const m = &GENERIC_POW5_TABLE[offset]; // 5^offset
542 const delta = pow5Bits(base2) - pow5Bits(i);
543
544 const shift: u6 = @intCast(2 * (i % 32));
545 const corr: u32 = @intCast(((POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1);
546 return mul_128_256_shift(m, mul, delta, corr);
547 }
548}
549
550fn computePow5(i: u32) [4]u64 {
551 const base = i / POW5_TABLE_SIZE;
552 const base2 = base * POW5_TABLE_SIZE;
553 const mul = &GENERIC_POW5_SPLIT[base];
554 if (i == base2) {
555 return mul.*;
556 } else {
557 const offset = i - base2;
558 const m = &GENERIC_POW5_TABLE[offset];
559 const delta = pow5Bits(i) - pow5Bits(base2);
560
561 const shift: u6 = @intCast(2 * (i % 32));
562 const corr: u32 = @intCast((POW5_ERRORS[i / 32] >> shift) & 3);
563 return mul_128_256_shift(m, mul, delta, corr);
564 }
565}
566
567fn mulShift(m: u128, mul: *const [4]u64, j: u32) u128 {
568 std.debug.assert(j > 128);
569 const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) };
570 const r = mul_128_256_shift(&a, mul, j, 0);
571 return (@as(u128, r[1]) << 64) | r[0];
572}
573
574fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 {
575 std.debug.assert(shift > 0);
576 std.debug.assert(shift < 256);
577
578 const b00 = @as(u128, a[0]) * b[0];
579 const b01 = @as(u128, a[0]) * b[1];
580 const b02 = @as(u128, a[0]) * b[2];
581 const b03 = @as(u128, a[0]) * b[3];
582 const b10 = @as(u128, a[1]) * b[0];
583 const b11 = @as(u128, a[1]) * b[1];
584 const b12 = @as(u128, a[1]) * b[2];
585 const b13 = @as(u128, a[1]) * b[3];
586
587 const s0 = b00;
588 const s1 = b01 +% b10;
589 const c1: u128 = @intFromBool(s1 < b01);
590 const s2 = b02 +% b11;
591 const c2: u128 = @intFromBool(s2 < b02);
592 const s3 = b03 +% b12;
593 const c3: u128 = @intFromBool(s3 < b03);
594
595 const p0 = s0 +% (s1 << 64);
596 const d0: u128 = @intFromBool(p0 < b00);
597 const q1 = s2 +% (s1 >> 64) +% (s3 << 64);
598 const d1: u128 = @intFromBool(q1 < s2);
599 const p1 = q1 +% (c1 << 64) +% d0;
600 const d2: u128 = @intFromBool(p1 < q1);
601 const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2;
602
603 var r0: u128 = undefined;
604 var r1: u128 = undefined;
605 if (shift < 128) {
606 const cshift: u7 = @intCast(shift);
607 const sshift: u7 = @intCast(128 - shift);
608 r0 = corr +% ((p0 >> cshift) | (p1 << sshift));
609 r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr);
610 } else if (shift == 128) {
611 r0 = corr +% p1;
612 r1 = p2 +% @intFromBool(r0 < corr);
613 } else {
614 const ashift: u7 = @intCast(shift - 128);
615 const sshift: u7 = @intCast(256 - shift);
616 r0 = corr +% ((p1 >> ashift) | (p2 << sshift));
617 r1 = (p2 >> ashift) +% @intFromBool(r0 < corr);
618 }
619
620 return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) };
621}
622
623// zig fmt: off
624//
625// 4.5KiB of tables.
626
627const FLOAT_128_POW5_INV_BITCOUNT = 249;
628const FLOAT_128_POW5_BITCOUNT = 249;
629const POW5_TABLE_SIZE = 56;
630
631const GENERIC_POW5_TABLE: [POW5_TABLE_SIZE][2]u64 = .{
632 .{ 1, 0 },
633 .{ 5, 0 },
634 .{ 25, 0 },
635 .{ 125, 0 },
636 .{ 625, 0 },
637 .{ 3125, 0 },
638 .{ 15625, 0 },
639 .{ 78125, 0 },
640 .{ 390625, 0 },
641 .{ 1953125, 0 },
642 .{ 9765625, 0 },
643 .{ 48828125, 0 },
644 .{ 244140625, 0 },
645 .{ 1220703125, 0 },
646 .{ 6103515625, 0 },
647 .{ 30517578125, 0 },
648 .{ 152587890625, 0 },
649 .{ 762939453125, 0 },
650 .{ 3814697265625, 0 },
651 .{ 19073486328125, 0 },
652 .{ 95367431640625, 0 },
653 .{ 476837158203125, 0 },
654 .{ 2384185791015625, 0 },
655 .{ 11920928955078125, 0 },
656 .{ 59604644775390625, 0 },
657 .{ 298023223876953125, 0 },
658 .{ 1490116119384765625, 0 },
659 .{ 7450580596923828125, 0 },
660 .{ 359414837200037393, 2 },
661 .{ 1797074186000186965, 10 },
662 .{ 8985370930000934825, 50 },
663 .{ 8033366502585570893, 252 },
664 .{ 3273344365508751233, 1262 },
665 .{ 16366721827543756165, 6310 },
666 .{ 8046632842880574361, 31554 },
667 .{ 3339676066983768573, 157772 },
668 .{ 16698380334918842865, 788860 },
669 .{ 9704925379756007861, 3944304 },
670 .{ 11631138751360936073, 19721522 },
671 .{ 2815461535676025517, 98607613 },
672 .{ 14077307678380127585, 493038065 },
673 .{ 15046306170771983077, 2465190328 },
674 .{ 1444554559021708921, 12325951644 },
675 .{ 7222772795108544605, 61629758220 },
676 .{ 17667119901833171409, 308148791101 },
677 .{ 14548623214327650581, 1540743955509 },
678 .{ 17402883850509598057, 7703719777548 },
679 .{ 13227442957709783821, 38518598887744 },
680 .{ 10796982567420264257, 192592994438723 },
681 .{ 17091424689682218053, 962964972193617 },
682 .{ 11670147153572883801, 4814824860968089 },
683 .{ 3010503546735764157, 24074124304840448 },
684 .{ 15052517733678820785, 120370621524202240 },
685 .{ 1475612373555897461, 601853107621011204 },
686 .{ 7378061867779487305, 3009265538105056020 },
687 .{ 18443565265187884909, 15046327690525280101 },
688};
689
690const GENERIC_POW5_SPLIT: [89][4]u64 = .{
691 .{ 0, 0, 0, 72057594037927936 },
692 .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 },
693 .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 },
694 .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 },
695 .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 },
696 .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 },
697 .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 },
698 .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 },
699 .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 },
700 .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 },
701 .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 },
702 .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 },
703 .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 },
704 .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 },
705 .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 },
706 .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 },
707 .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 },
708 .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 },
709 .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 },
710 .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 },
711 .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 },
712 .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 },
713 .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 },
714 .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 },
715 .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 },
716 .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 },
717 .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 },
718 .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 },
719 .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 },
720 .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 },
721 .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 },
722 .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 },
723 .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 },
724 .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 },
725 .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 },
726 .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 },
727 .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 },
728 .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 },
729 .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 },
730 .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 },
731 .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 },
732 .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 },
733 .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 },
734 .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 },
735 .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 },
736 .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 },
737 .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 },
738 .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 },
739 .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 },
740 .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 },
741 .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 },
742 .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 },
743 .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 },
744 .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 },
745 .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 },
746 .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 },
747 .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 },
748 .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 },
749 .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 },
750 .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 },
751 .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 },
752 .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 },
753 .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 },
754 .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 },
755 .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 },
756 .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 },
757 .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 },
758 .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 },
759 .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 },
760 .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 },
761 .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 },
762 .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 },
763 .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 },
764 .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 },
765 .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 },
766 .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 },
767 .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 },
768 .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 },
769 .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 },
770 .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 },
771 .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 },
772 .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 },
773 .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 },
774 .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 },
775 .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 },
776 .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 },
777 .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 },
778 .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 },
779 .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 },
780};
781
782// Unfortunately, the results are sometimes off by one or two. We use an additional
783// lookup table to store those cases and adjust the result.
784const POW5_ERRORS: [156]u64 = .{
785 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000,
786 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964,
787 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115,
788 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000,
789 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441,
790 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545,
791 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445,
792 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565,
793 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140,
794 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015,
795 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145,
796 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040,
797 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004,
798 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111,
799 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511,
800 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050,
801 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955,
802 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655,
803 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155,
804 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455,
805 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000,
806 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564,
807 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644,
808 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255,
809 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005,
810 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010,
811 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000,
812 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004,
813 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411,
814 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000,
815 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015,
816 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965,
817 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555,
818 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000,
819 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411,
820 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555,
821 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514,
822 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550,
823 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000,
824};
825
826const GENERIC_POW5_INV_SPLIT: [89][4]u64 = .{
827 .{ 0, 0, 0, 144115188075855872 },
828 .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 },
829 .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 },
830 .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 },
831 .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 },
832 .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 },
833 .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 },
834 .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 },
835 .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 },
836 .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 },
837 .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 },
838 .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 },
839 .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 },
840 .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 },
841 .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 },
842 .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 },
843 .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 },
844 .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 },
845 .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 },
846 .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 },
847 .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 },
848 .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 },
849 .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 },
850 .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 },
851 .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 },
852 .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 },
853 .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 },
854 .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 },
855 .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 },
856 .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 },
857 .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 },
858 .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 },
859 .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 },
860 .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 },
861 .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 },
862 .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 },
863 .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 },
864 .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 },
865 .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 },
866 .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 },
867 .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 },
868 .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 },
869 .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 },
870 .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 },
871 .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 },
872 .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 },
873 .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 },
874 .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 },
875 .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 },
876 .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 },
877 .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 },
878 .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 },
879 .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 },
880 .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 },
881 .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 },
882 .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 },
883 .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 },
884 .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 },
885 .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 },
886 .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 },
887 .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 },
888 .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 },
889 .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 },
890 .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 },
891 .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 },
892 .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 },
893 .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 },
894 .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 },
895 .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 },
896 .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 },
897 .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 },
898 .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 },
899 .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 },
900 .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 },
901 .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 },
902 .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 },
903 .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 },
904 .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 },
905 .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 },
906 .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 },
907 .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 },
908 .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 },
909 .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 },
910 .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 },
911 .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 },
912 .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 },
913 .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 },
914 .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 },
915 .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 },
916};
917
918const POW5_INV_ERRORS: [154]u64 = .{
919 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000,
920 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014,
921 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105,
922 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110,
923 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558,
924 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010,
925 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400,
926 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055,
927 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000,
928 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444,
929 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000,
930 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555,
931 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155,
932 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511,
933 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559,
934 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540,
935 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151,
936 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000,
937 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000,
938 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155,
939 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000,
940 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545,
941 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050,
942 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401,
943 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505,
944 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545,
945 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141,
946 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510,
947 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559,
948 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514,
949 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410,
950 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541,
951 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500,
952 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445,
953 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414,
954 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500,
955 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040,
956 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455,
957 0x0040000400105555, 0x0000000000000001,
958};
959
960// zig fmt: on
961
962fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
963 const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
964
965 var buf: [6000]u8 = undefined;
966 const value_bits: I = @bitCast(value);
967 const s = try format(&buf, value, .{});
968 try std.testing.expectEqualStrings(expected, s);
969
970 if (@bitSizeOf(T) != 80) {
971 const o = try std.fmt.parseFloat(T, s);
972 const o_bits: I = @bitCast(o);
973
974 if (std.math.isNan(value)) {
975 try std.testing.expect(std.math.isNan(o));
976 } else {
977 try std.testing.expectEqual(value_bits, o_bits);
978 }
979 }
980}
981
982test "format f32" {
983 try check(f32, 0.0, "0e0");
984 try check(f32, -0.0, "-0e0");
985 try check(f32, 1.0, "1e0");
986 try check(f32, -1.0, "-1e0");
987 try check(f32, std.math.nan(f32), "nan");
988 try check(f32, std.math.inf(f32), "inf");
989 try check(f32, -std.math.inf(f32), "-inf");
990 try check(f32, 1.1754944e-38, "1.1754944e-38");
991 try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38");
992 try check(f32, @bitCast(@as(u32, 1)), "1e-45");
993 try check(f32, 3.355445E7, "3.355445e7");
994 try check(f32, 8.999999e9, "9e9");
995 try check(f32, 3.4366717e10, "3.436672e10");
996 try check(f32, 3.0540412e5, "3.0540412e5");
997 try check(f32, 8.0990312e3, "8.0990312e3");
998 try check(f32, 2.4414062e-4, "2.4414062e-4");
999 try check(f32, 2.4414062e-3, "2.4414062e-3");
1000 try check(f32, 4.3945312e-3, "4.3945312e-3");
1001 try check(f32, 6.3476562e-3, "6.3476562e-3");
1002 try check(f32, 4.7223665e21, "4.7223665e21");
1003 try check(f32, 8388608.0, "8.388608e6");
1004 try check(f32, 1.6777216e7, "1.6777216e7");
1005 try check(f32, 3.3554436e7, "3.3554436e7");
1006 try check(f32, 6.7131496e7, "6.7131496e7");
1007 try check(f32, 1.9310392e-38, "1.9310392e-38");
1008 try check(f32, -2.47e-43, "-2.47e-43");
1009 try check(f32, 1.993244e-38, "1.993244e-38");
1010 try check(f32, 4103.9003, "4.1039004e3");
1011 try check(f32, 5.3399997e9, "5.3399997e9");
1012 try check(f32, 6.0898e-39, "6.0898e-39");
1013 try check(f32, 0.0010310042, "1.0310042e-3");
1014 try check(f32, 2.8823261e17, "2.882326e17");
1015 try check(f32, 7.038531e-26, "7.038531e-26");
1016 try check(f32, 9.2234038e17, "9.223404e17");
1017 try check(f32, 6.7108872e7, "6.710887e7");
1018 try check(f32, 1.0e-44, "1e-44");
1019 try check(f32, 2.816025e14, "2.816025e14");
1020 try check(f32, 9.223372e18, "9.223372e18");
1021 try check(f32, 1.5846085e29, "1.5846086e29");
1022 try check(f32, 1.1811161e19, "1.1811161e19");
1023 try check(f32, 5.368709e18, "5.368709e18");
1024 try check(f32, 4.6143165e18, "4.6143166e18");
1025 try check(f32, 0.007812537, "7.812537e-3");
1026 try check(f32, 1.4e-45, "1e-45");
1027 try check(f32, 1.18697724e20, "1.18697725e20");
1028 try check(f32, 1.00014165e-36, "1.00014165e-36");
1029 try check(f32, 200.0, "2e2");
1030 try check(f32, 3.3554432e7, "3.3554432e7");
1031
1032 try check(f32, 1.0, "1e0");
1033 try check(f32, 1.2, "1.2e0");
1034 try check(f32, 1.23, "1.23e0");
1035 try check(f32, 1.234, "1.234e0");
1036 try check(f32, 1.2345, "1.2345e0");
1037 try check(f32, 1.23456, "1.23456e0");
1038 try check(f32, 1.234567, "1.234567e0");
1039 try check(f32, 1.2345678, "1.2345678e0");
1040 try check(f32, 1.23456735e-36, "1.23456735e-36");
1041}
1042
1043test "format f64" {
1044 try check(f64, 0.0, "0e0");
1045 try check(f64, -0.0, "-0e0");
1046 try check(f64, 1.0, "1e0");
1047 try check(f64, -1.0, "-1e0");
1048 try check(f64, std.math.nan(f64), "nan");
1049 try check(f64, std.math.inf(f64), "inf");
1050 try check(f64, -std.math.inf(f64), "-inf");
1051 try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308");
1052 try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308");
1053 try check(f64, @bitCast(@as(u64, 1)), "5e-324");
1054 try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8");
1055 try check(f64, -2.109808898695963e16, "-2.109808898695963e16");
1056 try check(f64, 4.940656e-318, "4.940656e-318");
1057 try check(f64, 1.18575755e-316, "1.18575755e-316");
1058 try check(f64, 2.989102097996e-312, "2.989102097996e-312");
1059 try check(f64, 9.0608011534336e15, "9.0608011534336e15");
1060 try check(f64, 4.708356024711512e18, "4.708356024711512e18");
1061 try check(f64, 9.409340012568248e18, "9.409340012568248e18");
1062 try check(f64, 1.2345678, "1.2345678e0");
1063 try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39");
1064 try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40");
1065 try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40");
1066
1067 try check(f64, 1, "1e0");
1068 try check(f64, 1.2, "1.2e0");
1069 try check(f64, 1.23, "1.23e0");
1070 try check(f64, 1.234, "1.234e0");
1071 try check(f64, 1.2345, "1.2345e0");
1072 try check(f64, 1.23456, "1.23456e0");
1073 try check(f64, 1.234567, "1.234567e0");
1074 try check(f64, 1.2345678, "1.2345678e0");
1075 try check(f64, 1.23456789, "1.23456789e0");
1076 try check(f64, 1.234567895, "1.234567895e0");
1077 try check(f64, 1.2345678901, "1.2345678901e0");
1078 try check(f64, 1.23456789012, "1.23456789012e0");
1079 try check(f64, 1.234567890123, "1.234567890123e0");
1080 try check(f64, 1.2345678901234, "1.2345678901234e0");
1081 try check(f64, 1.23456789012345, "1.23456789012345e0");
1082 try check(f64, 1.234567890123456, "1.234567890123456e0");
1083 try check(f64, 1.2345678901234567, "1.2345678901234567e0");
1084
1085 try check(f64, 4.294967294, "4.294967294e0");
1086 try check(f64, 4.294967295, "4.294967295e0");
1087 try check(f64, 4.294967296, "4.294967296e0");
1088 try check(f64, 4.294967297, "4.294967297e0");
1089 try check(f64, 4.294967298, "4.294967298e0");
1090}
1091
1092test "format f80" {
1093 try check(f80, 0.0, "0e0");
1094 try check(f80, -0.0, "-0e0");
1095 try check(f80, 1.0, "1e0");
1096 try check(f80, -1.0, "-1e0");
1097 try check(f80, std.math.nan(f80), "nan");
1098 try check(f80, std.math.inf(f80), "inf");
1099 try check(f80, -std.math.inf(f80), "-inf");
1100
1101 try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308");
1102 try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8");
1103 try check(f80, -2.109808898695963e16, "-2.109808898695963e16");
1104 try check(f80, 4.940656e-318, "4.940656e-318");
1105 try check(f80, 1.18575755e-316, "1.18575755e-316");
1106 try check(f80, 2.989102097996e-312, "2.989102097996e-312");
1107 try check(f80, 9.0608011534336e15, "9.0608011534336e15");
1108 try check(f80, 4.708356024711512e18, "4.708356024711512e18");
1109 try check(f80, 9.409340012568248e18, "9.409340012568248e18");
1110 try check(f80, 1.2345678, "1.2345678e0");
1111}
1112
1113test "format f128" {
1114 try check(f128, 0.0, "0e0");
1115 try check(f128, -0.0, "-0e0");
1116 try check(f128, 1.0, "1e0");
1117 try check(f128, -1.0, "-1e0");
1118 try check(f128, std.math.nan(f128), "nan");
1119 try check(f128, std.math.inf(f128), "inf");
1120 try check(f128, -std.math.inf(f128), "-inf");
1121
1122 try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308");
1123 try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8");
1124 try check(f128, -2.109808898695963e16, "-2.109808898695963e16");
1125 try check(f128, 4.940656e-318, "4.940656e-318");
1126 try check(f128, 1.18575755e-316, "1.18575755e-316");
1127 try check(f128, 2.989102097996e-312, "2.989102097996e-312");
1128 try check(f128, 9.0608011534336e15, "9.0608011534336e15");
1129 try check(f128, 4.708356024711512e18, "4.708356024711512e18");
1130 try check(f128, 9.409340012568248e18, "9.409340012568248e18");
1131 try check(f128, 1.2345678, "1.2345678e0");
1132}
1133
1134test "format float to decimal with zero precision" {
1135 try expectFmt("5", "{d:.0}", .{5});
1136 try expectFmt("6", "{d:.0}", .{6});
1137 try expectFmt("7", "{d:.0}", .{7});
1138 try expectFmt("8", "{d:.0}", .{8});
1139}