authorgravatar for carl@astholm.seCarl Åstholm <carl@astholm.se> 2025-03-24 13:22:08+01:00
committergravatar for carl@astholm.seCarl Åstholm <carl@astholm.se> 2025-07-20 18:28:36+02:00
loge7604bba3ef0654a882edb17d712d1beb2cefec9
tree17394078bf60f61e2ed2bec53533d8785684a213
parent5380e81924dd98e9717eaf09ae05e935952a78ff

Serialize float options using the hexadecimal format

This ensures no information is lost when the value is round-tripped.

2 files changed, 12 insertions(+), 6 deletions(-)

lib/std/Build.zig+1-1
...@@ -507,7 +507,7 @@ fn addUserInputOptionFromArg(...@@ -507,7 +507,7 @@ fn addUserInputOptionFromArg(
507 .comptime_float, .float => return if (maybe_value) |v| {507 .comptime_float, .float => return if (maybe_value) |v| {
508 map.put(field.name, .{508 map.put(field.name, .{
509 .name = field.name,509 .name = field.name,
510 .value = .{ .scalar = std.fmt.allocPrint(arena, "{e}", .{v}) catch @panic("OOM") },510 .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
511 .used = false,511 .used = false,
512 }) catch @panic("OOM");512 }) catch @panic("OOM");
513 },513 },
lib/std/Io/Writer.zig+11-5
...@@ -1563,17 +1563,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)...@@ -1563,17 +1563,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
1563}1563}
15641564
1565pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {1565pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1566 if (std.math.signbit(value)) try w.writeByte('-');1566 const v = switch (@TypeOf(value)) {
1567 if (std.math.isNan(value)) return w.writeAll(switch (case) {1567 // comptime_float internally is a f128; this preserves precision.
1568 comptime_float => @as(f128, value),
1569 else => value,
1570 };
1571
1572 if (std.math.signbit(v)) try w.writeByte('-');
1573 if (std.math.isNan(v)) return w.writeAll(switch (case) {
1568 .lower => "nan",1574 .lower => "nan",
1569 .upper => "NAN",1575 .upper => "NAN",
1570 });1576 });
1571 if (std.math.isInf(value)) return w.writeAll(switch (case) {1577 if (std.math.isInf(v)) return w.writeAll(switch (case) {
1572 .lower => "inf",1578 .lower => "inf",
1573 .upper => "INF",1579 .upper => "INF",
1574 });1580 });
15751581
1576 const T = @TypeOf(value);1582 const T = @TypeOf(v);
1577 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));1583 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
15781584
1579 const mantissa_bits = std.math.floatMantissaBits(T);1585 const mantissa_bits = std.math.floatMantissaBits(T);
...@@ -1583,7 +1589,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi...@@ -1583,7 +1589,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
1583 const exponent_mask = (1 << exponent_bits) - 1;1589 const exponent_mask = (1 << exponent_bits) - 1;
1584 const exponent_bias = (1 << (exponent_bits - 1)) - 1;1590 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15851591
1586 const as_bits: TU = @bitCast(value);1592 const as_bits: TU = @bitCast(v);
1587 var mantissa = as_bits & mantissa_mask;1593 var mantissa = as_bits & mantissa_mask;
1588 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));1594 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
15891595