authorgravatar for radomski.main@protonmail.comMateusz Radomski <radomski.main@protonmail.com> 2022-01-31 09:54:19+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-31 20:59:32-07:00
log7f024d6786b690e7980d6e47d7ae70fa8528a0df
tree6b7ffeda08e97cfe833359aa1c3769f80c3bb2d5
parent627cf6ce482349c172150d058660f7a1646c2aac

std: correct rounding in parse_hex_float.zig


2 files changed, 13 insertions(+), 14 deletions(-)

lib/std/fmt/parse_hex_float.zig+13-9
...@@ -202,18 +202,21 @@ pub fn parseHexFloat(comptime T: type, s: []const u8) !T {...@@ -202,18 +202,21 @@ pub fn parseHexFloat(comptime T: type, s: []const u8) !T {
202 exponent += 1;202 exponent += 1;
203 }203 }
204204
205 // There are two cases to handle:205 // Whenever the guard bit is one (G=1) and:
206 // - We've truncated more than 0.5ULP (R=S=1), increase the mantissa.206 // - we've truncated more than 0.5ULP (R=S=1)
207 // - We've truncated exactly 0.5ULP (R=1 S=0), increase the mantissa if the207 // - we've truncated exactly 0.5ULP (R=1 S=0)
208 // result is odd (G=1).208 // Were are going to increase the mantissa (round up)
209 // The two checks can be neatly folded as follows.209 var exactly_half = (mantissa & 0b11) == 0b10;
210 mantissa |= @boolToInt(mantissa & 0b100 != 0);210 var more_than_half = (mantissa & 0b11) == 0b11;
211 mantissa += 1;
212
213 mantissa >>= 2;211 mantissa >>= 2;
212 var guardBit = mantissa & 1 == 1;
214 exponent += 2;213 exponent += 2;
215214
216 if (mantissa & (1 << (mantissa_bits + 1)) != 0) {215 if (guardBit and (exactly_half or more_than_half)) {
216 mantissa += 1;
217 }
218
219 if (mantissa == (1 << (mantissa_bits + 1))) {
217 // Renormalize, if the exponent overflows we'll catch that below.220 // Renormalize, if the exponent overflows we'll catch that below.
218 mantissa >>= 1;221 mantissa >>= 1;
219 exponent += 1;222 exponent += 1;
...@@ -338,6 +341,7 @@ test "f128" {...@@ -338,6 +341,7 @@ test "f128" {
338 // // Min denormalized value.341 // // Min denormalized value.
339 .{ .s = "0x1p-16494", .v = math.f128_true_min },342 .{ .s = "0x1p-16494", .v = math.f128_true_min },
340 .{ .s = "-0x1p-16494", .v = -math.f128_true_min },343 .{ .s = "-0x1p-16494", .v = -math.f128_true_min },
344 .{ .s = "0x1.edcb34a235253948765432134674fp-1", .v = 0x1.edcb34a235253948765432134674fp-1 },
341 };345 };
342346
343 for (cases) |case| {347 for (cases) |case| {
test/behavior/math.zig-5
...@@ -632,11 +632,6 @@ test "allow signed integer division/remainder when values are comptime known and...@@ -632,11 +632,6 @@ test "allow signed integer division/remainder when values are comptime known and
632}632}
633633
634test "quad hex float literal parsing accurate" {634test "quad hex float literal parsing accurate" {
635 if (builtin.zig_backend != .stage1) {
636 // TODO https://github.com/ziglang/zig/issues/10737
637 return error.SkipZigTest;
638 }
639
640 const a: f128 = 0x1.1111222233334444555566667777p+0;635 const a: f128 = 0x1.1111222233334444555566667777p+0;
641636
642 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.637 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.