use scientific notation for very large/very small values
This commit is contained in:
parent
ae2b10a5cc
commit
3262be27ba
2 changed files with 77 additions and 0 deletions
|
|
@ -688,6 +688,9 @@ IEEE 754 float interpretation:
|
|||
- Significand: another color (e.g. green)
|
||||
- Display below the bit grid shows:
|
||||
- Decimal value (exact)
|
||||
- Value and ULP use scientific notation for very small/large
|
||||
magnitudes (e.g. a subnormal ULP shows as `1.4e-45`), fixed-point
|
||||
otherwise, so each row stays on one line
|
||||
- Formula: (-1)^s * 2^(e-bias) * 1.mantissa
|
||||
- Classification: normal, denormal, zero, infinity, NaN
|
||||
- ULP: delta to next representable value
|
||||
|
|
|
|||
|
|
@ -55,6 +55,24 @@ pub fn formatFloat(buf: []u8, value: f64) FormattedValue {
|
|||
return .{ .display = buf[0..raw_len], .raw = buf[0..raw_len] };
|
||||
}
|
||||
|
||||
/// Format a float for compact single-line display (used by the float view).
|
||||
/// Uses shortest round-trip fixed-point for normal magnitudes, and scientific
|
||||
/// notation for very small or very large magnitudes so rows stay readable
|
||||
/// (e.g. a subnormal ULP prints as "1.4e-45" instead of 45 decimal digits).
|
||||
/// Non-finite values render as "inf", "-inf", or "nan".
|
||||
pub fn formatCompactFloat(buf: []u8, value: f64) []const u8 {
|
||||
if (std.math.isNan(value)) return "nan";
|
||||
if (std.math.isPositiveInf(value)) return "inf";
|
||||
if (std.math.isNegativeInf(value)) return "-inf";
|
||||
|
||||
const abs = @abs(value);
|
||||
const use_scientific = abs != 0 and (abs < 1e-4 or abs >= 1e16);
|
||||
if (use_scientific) {
|
||||
return std.fmt.bufPrint(buf, "{e}", .{value}) catch return "ERR";
|
||||
}
|
||||
return std.fmt.bufPrint(buf, "{d}", .{value}) catch return "ERR";
|
||||
}
|
||||
|
||||
/// Format an integer for programmer mode hex display.
|
||||
/// Display: "FF FF FF FF" (space per byte), byte order per `endian`.
|
||||
/// Raw: "0xFFFFFFFF" (no separators, canonical MSB-first value regardless of
|
||||
|
|
@ -569,3 +587,59 @@ test "formatAscii: 0x7F is non-printable" {
|
|||
const result = formatAscii(&buf, 0x7F, .bits8, .big);
|
||||
try testing.expectEqualStrings(".", result.raw);
|
||||
}
|
||||
|
||||
fn hasChar(s: []const u8, c: u8) bool {
|
||||
return std.mem.indexOfScalar(u8, s, c) != null;
|
||||
}
|
||||
|
||||
test "formatCompactFloat: normal magnitudes use fixed-point" {
|
||||
var buf: [64]u8 = undefined;
|
||||
try testing.expect(!hasChar(formatCompactFloat(&buf, 1.0), 'e'));
|
||||
try testing.expect(!hasChar(formatCompactFloat(&buf, 3.14), 'e'));
|
||||
try testing.expect(!hasChar(formatCompactFloat(&buf, 0.5), 'e'));
|
||||
try testing.expect(!hasChar(formatCompactFloat(&buf, -2.0), 'e'));
|
||||
// Just above the small-magnitude threshold stays fixed-point
|
||||
try testing.expect(!hasChar(formatCompactFloat(&buf, 0.001), 'e'));
|
||||
}
|
||||
|
||||
test "formatCompactFloat: 3.14 renders exactly" {
|
||||
var buf: [64]u8 = undefined;
|
||||
try testing.expectEqualStrings("3.14", formatCompactFloat(&buf, 3.14));
|
||||
}
|
||||
|
||||
test "formatCompactFloat: preserves round-trip precision for normal magnitude" {
|
||||
var buf: [64]u8 = undefined;
|
||||
// 0.1 stored as f32 then widened: normal magnitude, so fixed-point and full
|
||||
const v: f64 = @floatCast(@as(f32, 0.1));
|
||||
const s = formatCompactFloat(&buf, v);
|
||||
try testing.expect(!hasChar(s, 'e'));
|
||||
try testing.expect(std.mem.startsWith(u8, s, "0.100000001"));
|
||||
}
|
||||
|
||||
test "formatCompactFloat: very small magnitudes use scientific" {
|
||||
var buf: [64]u8 = undefined;
|
||||
// smallest f32 subnormal ~ 1.4e-45
|
||||
try testing.expect(hasChar(formatCompactFloat(&buf, std.math.ldexp(@as(f64, 1.0), -149)), 'e'));
|
||||
// f32 ULP of 1.0 = 2^-23 ~ 1.19e-7
|
||||
try testing.expect(hasChar(formatCompactFloat(&buf, std.math.ldexp(@as(f64, 1.0), -23)), 'e'));
|
||||
// f64 ULP of 1.0 = 2^-52 ~ 2.2e-16
|
||||
try testing.expect(hasChar(formatCompactFloat(&buf, std.math.ldexp(@as(f64, 1.0), -52)), 'e'));
|
||||
}
|
||||
|
||||
test "formatCompactFloat: very large magnitudes use scientific" {
|
||||
var buf: [64]u8 = undefined;
|
||||
try testing.expect(hasChar(formatCompactFloat(&buf, 1e20), 'e'));
|
||||
try testing.expect(hasChar(formatCompactFloat(&buf, -1e18), 'e'));
|
||||
}
|
||||
|
||||
test "formatCompactFloat: zero is fixed-point, not scientific" {
|
||||
var buf: [64]u8 = undefined;
|
||||
try testing.expectEqualStrings("0", formatCompactFloat(&buf, 0.0));
|
||||
}
|
||||
|
||||
test "formatCompactFloat: non-finite values" {
|
||||
var buf: [64]u8 = undefined;
|
||||
try testing.expectEqualStrings("inf", formatCompactFloat(&buf, std.math.inf(f64)));
|
||||
try testing.expectEqualStrings("-inf", formatCompactFloat(&buf, -std.math.inf(f64)));
|
||||
try testing.expectEqualStrings("nan", formatCompactFloat(&buf, std.math.nan(f64)));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue