| ... | @@ -906,24 +906,31 @@ fn formatUnicodeCodepoint(c: u21, options: FormatOptions, writer: anytype) !void | ... | @@ -906,24 +906,31 @@ fn formatUnicodeCodepoint(c: u21, options: FormatOptions, writer: anytype) !void |
| 906 | } | 906 | } |
| 907 | | 907 | |
| 908 | fn formatFloatValue(value: anytype, comptime fmt: []const u8, options: FormatOptions, writer: anytype) !void { | 908 | fn formatFloatValue(value: anytype, comptime fmt: []const u8, options: FormatOptions, writer: anytype) !void { |
| 909 | var buf: [std.fmt.format_float.bufferSize(.decimal, f64)]u8 = undefined; | 909 | const v = switch (@TypeOf(value)) { |
| | 910 | comptime_float => @as(f128, value), // comptime_float internally is a f128; this preserves precision. |
| | 911 | else => value, |
| | 912 | }; |
| | 913 | const T = @TypeOf(v); |
| | 914 | comptime std.debug.assert(@typeInfo(T) == .float); |
| | 915 | const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); |
| | 916 | const DT = if (@bitSizeOf(T) <= 64) u64 else u128; |
| | 917 | const tables = switch (DT) { |
| | 918 | u64 => &std.fmt.float.Backend64_TablesFull, |
| | 919 | u128 => &std.fmt.float.Backend128_Tables, |
| | 920 | else => unreachable, |
| | 921 | }; |
| | 922 | const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0; |
| | 923 | const d = std.fmt.float.binaryToDecimal(DT, @as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit, tables); |
| | 924 | var buf: [std.fmt.float.bufferSize(.decimal, T)]u8 = undefined; |
| 910 | | 925 | |
| 911 | if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) { | 926 | if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) { |
| 912 | const s = std.fmt.formatFloat(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { | 927 | try writer.writeAll(std.fmt.float.formatScientific(DT, &buf, d, options.precision) catch unreachable); |
| 913 | error.BufferTooSmall => "(float)", | | |
| 914 | }; | | |
| 915 | return formatBuf(s, options, writer); | | |
| 916 | } else if (comptime std.mem.eql(u8, fmt, "d")) { | 928 | } else if (comptime std.mem.eql(u8, fmt, "d")) { |
| 917 | const s = std.fmt.formatFloat(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { | 929 | try writer.writeAll(std.fmt.float.formatDecimal(DT, &buf, d, options.precision) catch unreachable); |
| 918 | error.BufferTooSmall => "(float)", | | |
| 919 | }; | | |
| 920 | return formatBuf(s, options, writer); | | |
| 921 | } else if (comptime std.mem.eql(u8, fmt, "x")) { | 930 | } else if (comptime std.mem.eql(u8, fmt, "x")) { |
| 922 | var buf_stream: nio.FixedBufferStream([]u8) = .init(&buf); | 931 | var w: std.Io.Writer = .fixed(&buf); |
| 923 | std.fmt.formatFloatHexadecimal(value, options, &buf_stream) catch |err| switch (err) { | 932 | w.printFloatHex(v, .lower, options.precision) catch unreachable; |
| 924 | error.NoSpaceLeft => unreachable, | 933 | try writer.writeAll(buf[0..w.end]); |
| 925 | }; | | |
| 926 | return formatBuf(buf_stream.written(), options, writer); | | |
| 927 | } else { | 934 | } else { |
| 928 | invalidFmtError(fmt, value); | 935 | invalidFmtError(fmt, value); |
| 929 | } | 936 | } |