Function printFloatHex [src]

Prototype

pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void

Parameters

w: *Writercase: std.fmt.Caseopt_precision: ?usize

Possible Errors

WriteFailed

See the Writer implementation for detailed diagnostics.

Source

pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void { const v = switch (@TypeOf(value)) { // comptime_float internally is a f128; this preserves precision. comptime_float => @as(f128, value), else => value, }; if (std.math.signbit(v)) try w.writeByte('-'); if (std.math.isNan(v)) return w.writeAll(switch (case) { .lower => "nan", .upper => "NAN", }); if (std.math.isInf(v)) return w.writeAll(switch (case) { .lower => "inf", .upper => "INF", }); const T = @TypeOf(v); const TU = std.meta.Int(.unsigned, @bitSizeOf(T)); const mantissa_bits = std.math.floatMantissaBits(T); const fractional_bits = std.math.floatFractionalBits(T); const exponent_bits = std.math.floatExponentBits(T); const mantissa_mask = (1 << mantissa_bits) - 1; const exponent_mask = (1 << exponent_bits) - 1; const exponent_bias = (1 << (exponent_bits - 1)) - 1; const as_bits: TU = @bitCast(v); var mantissa = as_bits & mantissa_mask; var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask)); const is_denormal = exponent == 0 and mantissa != 0; const is_zero = exponent == 0 and mantissa == 0; if (is_zero) { // Handle this case here to simplify the logic below. try w.writeAll("0x0"); if (opt_precision) |precision| { if (precision > 0) { try w.writeAll("."); try w.splatByteAll('0', precision); } } else { try w.writeAll(".0"); } try w.writeAll("p0"); return; } if (is_denormal) { // Adjust the exponent for printing. exponent += 1; } else { if (fractional_bits == mantissa_bits) mantissa |= 1 << fractional_bits; // Add the implicit integer bit. } const mantissa_digits = (fractional_bits + 3) / 4; // Fill in zeroes to round the fraction width to a multiple of 4. mantissa <<= mantissa_digits * 4 - fractional_bits; if (opt_precision) |precision| { // Round if needed. if (precision < mantissa_digits) { // We always have at least 4 extra bits. var extra_bits = (mantissa_digits - precision) * 4; // The result LSB is the Guard bit, we need two more (Round and // Sticky) to round the value. while (extra_bits > 2) { mantissa = (mantissa >> 1) | (mantissa & 1); extra_bits -= 1; } // Round to nearest, tie to even. mantissa |= @intFromBool(mantissa & 0b100 != 0); mantissa += 1; // Drop the excess bits. mantissa >>= 2; // Restore the alignment. mantissa <<= @as(std.math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4)); const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0; // Prefer a normalized result in case of overflow. if (overflow) { mantissa >>= 1; exponent += 1; } } } // +1 for the decimal part. var buf: [1 + mantissa_digits]u8 = undefined; assert(std.fmt.printInt(&buf, mantissa, 16, case, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len); try w.writeAll("0x"); try w.writeByte(buf[0]); const trimmed = std.mem.trimRight(u8, buf[1..], "0"); if (opt_precision) |precision| { if (precision > 0) try w.writeAll("."); } else if (trimmed.len > 0) { try w.writeAll("."); } try w.writeAll(trimmed); // Add trailing zeros if explicitly requested. if (opt_precision) |precision| if (precision > 0) { if (precision > trimmed.len) try w.splatByteAll('0', precision - trimmed.len); }; try w.writeAll("p"); try w.printInt(exponent - exponent_bias, 10, case, .{}); }