From 7f024d6786b690e7980d6e47d7ae70fa8528a0df Mon Sep 17 00:00:00 2001 From: Mateusz Radomski Date: Mon, 31 Jan 2022 09:54:19 +0100 Subject: std: correct rounding in parse_hex_float.zig --- lib/std/fmt/parse_hex_float.zig | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'lib/std/fmt/parse_hex_float.zig') diff --git a/lib/std/fmt/parse_hex_float.zig b/lib/std/fmt/parse_hex_float.zig index 45a289fdd2..5057823394 100644 --- a/lib/std/fmt/parse_hex_float.zig +++ b/lib/std/fmt/parse_hex_float.zig @@ -202,18 +202,21 @@ pub fn parseHexFloat(comptime T: type, s: []const u8) !T { exponent += 1; } - // There are two cases to handle: - // - We've truncated more than 0.5ULP (R=S=1), increase the mantissa. - // - We've truncated exactly 0.5ULP (R=1 S=0), increase the mantissa if the - // result is odd (G=1). - // The two checks can be neatly folded as follows. - mantissa |= @boolToInt(mantissa & 0b100 != 0); - mantissa += 1; - + // Whenever the guard bit is one (G=1) and: + // - we've truncated more than 0.5ULP (R=S=1) + // - we've truncated exactly 0.5ULP (R=1 S=0) + // Were are going to increase the mantissa (round up) + var exactly_half = (mantissa & 0b11) == 0b10; + var more_than_half = (mantissa & 0b11) == 0b11; mantissa >>= 2; + var guardBit = mantissa & 1 == 1; exponent += 2; - if (mantissa & (1 << (mantissa_bits + 1)) != 0) { + if (guardBit and (exactly_half or more_than_half)) { + mantissa += 1; + } + + if (mantissa == (1 << (mantissa_bits + 1))) { // Renormalize, if the exponent overflows we'll catch that below. mantissa >>= 1; exponent += 1; @@ -338,6 +341,7 @@ test "f128" { // // Min denormalized value. .{ .s = "0x1p-16494", .v = math.f128_true_min }, .{ .s = "-0x1p-16494", .v = -math.f128_true_min }, + .{ .s = "0x1.edcb34a235253948765432134674fp-1", .v = 0x1.edcb34a235253948765432134674fp-1 }, }; for (cases) |case| { -- cgit v1.2.3 From c46f7588cea98c48e6c7f637e13536378027e260 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 31 Jan 2022 20:57:05 -0700 Subject: std.fmt.parseHexFloat: clean up bitwise logic * fold a couple separate operations into one * use const instead of var * naming conventions --- lib/std/fmt/parse_hex_float.zig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib/std/fmt/parse_hex_float.zig') diff --git a/lib/std/fmt/parse_hex_float.zig b/lib/std/fmt/parse_hex_float.zig index 5057823394..83c798ab96 100644 --- a/lib/std/fmt/parse_hex_float.zig +++ b/lib/std/fmt/parse_hex_float.zig @@ -206,13 +206,11 @@ pub fn parseHexFloat(comptime T: type, s: []const u8) !T { // - we've truncated more than 0.5ULP (R=S=1) // - we've truncated exactly 0.5ULP (R=1 S=0) // Were are going to increase the mantissa (round up) - var exactly_half = (mantissa & 0b11) == 0b10; - var more_than_half = (mantissa & 0b11) == 0b11; + const guard_bit_and_half_or_more = (mantissa & 0b110) == 0b110; mantissa >>= 2; - var guardBit = mantissa & 1 == 1; exponent += 2; - if (guardBit and (exactly_half or more_than_half)) { + if (guard_bit_and_half_or_more) { mantissa += 1; } -- cgit v1.2.3