| author | |
| committer | |
| log | 8ff01f78f314a743df8c8f085a02416bb1ce0c72 |
| tree | 052e28d9141c7d4a04c7680beedd34d6b04f91f5 |
| parent | 959d227d1370c9cf9198ed111e3a8bca15a7e47b |
7 files changed, 79 insertions(+), 33 deletions(-)
lib/std/fmt/format_float.zig+6-8| ... | @@ -1521,15 +1521,13 @@ fn check(comptime T: type, value: T, comptime expected: []const u8) !void { | ... | @@ -1521,15 +1521,13 @@ fn check(comptime T: type, value: T, comptime expected: []const u8) !void { |
| 1521 | const s = try formatFloat(&buf, value, .{}); | 1521 | const s = try formatFloat(&buf, value, .{}); |
| 1522 | try std.testing.expectEqualStrings(expected, s); | 1522 | try std.testing.expectEqualStrings(expected, s); |
| 1523 | 1523 | ||
| 1524 | if (@bitSizeOf(T) != 80) { | 1524 | const o = try std.fmt.parseFloat(T, s); |
| 1525 | const o = try std.fmt.parseFloat(T, s); | 1525 | const o_bits: I = @bitCast(o); |
| 1526 | const o_bits: I = @bitCast(o); | ||
| 1527 | 1526 | ||
| 1528 | if (std.math.isNan(value)) { | 1527 | if (std.math.isNan(value)) { |
| 1529 | try std.testing.expect(std.math.isNan(o)); | 1528 | try std.testing.expect(std.math.isNan(o)); |
| 1530 | } else { | 1529 | } else { |
| 1531 | try std.testing.expectEqual(value_bits, o_bits); | 1530 | try std.testing.expectEqual(value_bits, o_bits); |
| 1532 | } | ||
| 1533 | } | 1531 | } |
| 1534 | } | 1532 | } |
| 1535 | 1533 |
lib/std/fmt/parse_float.zig+24-9| ... | @@ -21,10 +21,6 @@ pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T { | ... | @@ -21,10 +21,6 @@ pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T { |
| 21 | @compileError("Cannot parse a float into a non-floating point type."); | 21 | @compileError("Cannot parse a float into a non-floating point type."); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | if (T == f80) { | ||
| 25 | @compileError("TODO support parsing float to f80"); | ||
| 26 | } | ||
| 27 | |||
| 28 | if (s.len == 0) { | 24 | if (s.len == 0) { |
| 29 | return error.InvalidCharacter; | 25 | return error.InvalidCharacter; |
| 30 | } | 26 | } |
| ... | @@ -75,7 +71,7 @@ pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T { | ... | @@ -75,7 +71,7 @@ pub fn parseFloat(comptime T: type, s: []const u8) ParseFloatError!T { |
| 75 | // See https://github.com/tiehuis/parse-number-fxx-test-data for a wider-selection of test-data. | 71 | // See https://github.com/tiehuis/parse-number-fxx-test-data for a wider-selection of test-data. |
| 76 | 72 | ||
| 77 | test parseFloat { | 73 | test parseFloat { |
| 78 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | 74 | inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { |
| 79 | try testing.expectError(error.InvalidCharacter, parseFloat(T, "")); | 75 | try testing.expectError(error.InvalidCharacter, parseFloat(T, "")); |
| 80 | try testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); | 76 | try testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); |
| 81 | try testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc")); | 77 | try testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc")); |
| ... | @@ -131,7 +127,7 @@ test parseFloat { | ... | @@ -131,7 +127,7 @@ test parseFloat { |
| 131 | } | 127 | } |
| 132 | 128 | ||
| 133 | test "nan and inf" { | 129 | test "nan and inf" { |
| 134 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | 130 | inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { |
| 135 | const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | 131 | const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); |
| 136 | 132 | ||
| 137 | try expectEqual(@as(Z, @bitCast(try parseFloat(T, "nAn"))), @as(Z, @bitCast(std.math.nan(T)))); | 133 | try expectEqual(@as(Z, @bitCast(try parseFloat(T, "nAn"))), @as(Z, @bitCast(std.math.nan(T)))); |
| ... | @@ -144,6 +140,7 @@ test "largest normals" { | ... | @@ -144,6 +140,7 @@ test "largest normals" { |
| 144 | try expectEqual(@as(u16, @bitCast(try parseFloat(f16, "65504"))), 0x7bff); | 140 | try expectEqual(@as(u16, @bitCast(try parseFloat(f16, "65504"))), 0x7bff); |
| 145 | try expectEqual(@as(u32, @bitCast(try parseFloat(f32, "3.4028234664E38"))), 0x7f7f_ffff); | 141 | try expectEqual(@as(u32, @bitCast(try parseFloat(f32, "3.4028234664E38"))), 0x7f7f_ffff); |
| 146 | try expectEqual(@as(u64, @bitCast(try parseFloat(f64, "1.7976931348623157E308"))), 0x7fef_ffff_ffff_ffff); | 142 | try expectEqual(@as(u64, @bitCast(try parseFloat(f64, "1.7976931348623157E308"))), 0x7fef_ffff_ffff_ffff); |
| 143 | try expectEqual(@as(u80, @bitCast(try parseFloat(f80, "1.189731495357231765E4932"))), 0x7ffe_ffff_ffff_ffff_ffff); | ||
| 147 | try expectEqual(@as(u128, @bitCast(try parseFloat(f128, "1.1897314953572317650857593266280070162E4932"))), 0x7ffe_ffff_ffff_ffff_ffff_ffff_ffff_ffff); | 144 | try expectEqual(@as(u128, @bitCast(try parseFloat(f128, "1.1897314953572317650857593266280070162E4932"))), 0x7ffe_ffff_ffff_ffff_ffff_ffff_ffff_ffff); |
| 148 | } | 145 | } |
| 149 | 146 | ||
| ... | @@ -152,8 +149,8 @@ test "#11169" { | ... | @@ -152,8 +149,8 @@ test "#11169" { |
| 152 | } | 149 | } |
| 153 | 150 | ||
| 154 | test "many_digits hex" { | 151 | test "many_digits hex" { |
| 155 | const a: f32 = try std.fmt.parseFloat(f32, "0xffffffffffffffff.0p0"); | 152 | const a: f32 = try parseFloat(f32, "0xffffffffffffffff.0p0"); |
| 156 | const b: f32 = @floatCast(try std.fmt.parseFloat(f128, "0xffffffffffffffff.0p0")); | 153 | const b: f32 = @floatCast(try parseFloat(f128, "0xffffffffffffffff.0p0")); |
| 157 | try std.testing.expectEqual(a, b); | 154 | try std.testing.expectEqual(a, b); |
| 158 | } | 155 | } |
| 159 | 156 | ||
| ... | @@ -163,6 +160,7 @@ test "hex.special" { | ... | @@ -163,6 +160,7 @@ test "hex.special" { |
| 163 | try testing.expect(math.isPositiveInf(try parseFloat(f32, "+Inf"))); | 160 | try testing.expect(math.isPositiveInf(try parseFloat(f32, "+Inf"))); |
| 164 | try testing.expect(math.isNegativeInf(try parseFloat(f32, "-iNf"))); | 161 | try testing.expect(math.isNegativeInf(try parseFloat(f32, "-iNf"))); |
| 165 | } | 162 | } |
| 163 | |||
| 166 | test "hex.zero" { | 164 | test "hex.zero" { |
| 167 | try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "0x0")); | 165 | try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "0x0")); |
| 168 | try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "-0x0")); | 166 | try testing.expectEqual(@as(f32, 0.0), try parseFloat(f32, "-0x0")); |
| ... | @@ -221,6 +219,23 @@ test "hex.f64" { | ... | @@ -221,6 +219,23 @@ test "hex.f64" { |
| 221 | try testing.expectEqual(try parseFloat(f64, "0x1p-1074"), math.floatTrueMin(f64)); | 219 | try testing.expectEqual(try parseFloat(f64, "0x1p-1074"), math.floatTrueMin(f64)); |
| 222 | try testing.expectEqual(try parseFloat(f64, "-0x1p-1074"), -math.floatTrueMin(f64)); | 220 | try testing.expectEqual(try parseFloat(f64, "-0x1p-1074"), -math.floatTrueMin(f64)); |
| 223 | } | 221 | } |
| 222 | |||
| 223 | test "hex.f80" { | ||
| 224 | try testing.expectEqual(try parseFloat(f80, "0x1p0"), 1.0); | ||
| 225 | try testing.expectEqual(try parseFloat(f80, "-0x1p-1"), -0.5); | ||
| 226 | try testing.expectEqual(try parseFloat(f80, "0x10p+10"), 16384.0); | ||
| 227 | try testing.expectEqual(try parseFloat(f80, "0x10p-10"), 0.015625); | ||
| 228 | // Max normalized value. | ||
| 229 | try testing.expectEqual(try parseFloat(f80, "0xf.fffffffffffffff7p+16380"), math.floatMax(f80)); | ||
| 230 | try testing.expectEqual(try parseFloat(f80, "-0xf.fffffffffffffff7p+16380"), -math.floatMax(f80)); | ||
| 231 | // Min normalized value. | ||
| 232 | try testing.expectEqual(try parseFloat(f80, "0x1p-16382"), math.floatMin(f80)); | ||
| 233 | try testing.expectEqual(try parseFloat(f80, "-0x1p-16382"), -math.floatMin(f80)); | ||
| 234 | // Min denormalized value. | ||
| 235 | try testing.expectEqual(try parseFloat(f80, "0x1p-16445"), math.floatTrueMin(f80)); | ||
| 236 | try testing.expectEqual(try parseFloat(f80, "-0x1p-16445"), -math.floatTrueMin(f80)); | ||
| 237 | } | ||
| 238 | |||
| 224 | test "hex.f128" { | 239 | test "hex.f128" { |
| 225 | try testing.expectEqual(try parseFloat(f128, "0x1p0"), 1.0); | 240 | try testing.expectEqual(try parseFloat(f128, "0x1p0"), 1.0); |
| 226 | try testing.expectEqual(try parseFloat(f128, "-0x1p-1"), -0.5); | 241 | try testing.expectEqual(try parseFloat(f128, "-0x1p-1"), -0.5); |
| ... | @@ -232,7 +247,7 @@ test "hex.f128" { | ... | @@ -232,7 +247,7 @@ test "hex.f128" { |
| 232 | // Min normalized value. | 247 | // Min normalized value. |
| 233 | try testing.expectEqual(try parseFloat(f128, "0x1p-16382"), math.floatMin(f128)); | 248 | try testing.expectEqual(try parseFloat(f128, "0x1p-16382"), math.floatMin(f128)); |
| 234 | try testing.expectEqual(try parseFloat(f128, "-0x1p-16382"), -math.floatMin(f128)); | 249 | try testing.expectEqual(try parseFloat(f128, "-0x1p-16382"), -math.floatMin(f128)); |
| 235 | // // Min denormalized value. | 250 | // Min denormalized value. |
| 236 | try testing.expectEqual(try parseFloat(f128, "0x1p-16494"), math.floatTrueMin(f128)); | 251 | try testing.expectEqual(try parseFloat(f128, "0x1p-16494"), math.floatTrueMin(f128)); |
| 237 | try testing.expectEqual(try parseFloat(f128, "-0x1p-16494"), -math.floatTrueMin(f128)); | 252 | try testing.expectEqual(try parseFloat(f128, "-0x1p-16494"), -math.floatTrueMin(f128)); |
| 238 | // ensure round-to-even | 253 | // ensure round-to-even |
lib/std/fmt/parse_float/FloatInfo.zig+23-3| ... | @@ -60,7 +60,7 @@ pub fn from(comptime T: type) Self { | ... | @@ -60,7 +60,7 @@ pub fn from(comptime T: type) Self { |
| 60 | .max_exponent_fast_path_disguised = 7, | 60 | .max_exponent_fast_path_disguised = 7, |
| 61 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), | 61 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), |
| 62 | // Slow + Eisel-Lemire | 62 | // Slow + Eisel-Lemire |
| 63 | .mantissa_explicit_bits = std.math.floatMantissaBits(T), | 63 | .mantissa_explicit_bits = std.math.floatFractionalBits(T), |
| 64 | .infinite_power = 0x1f, | 64 | .infinite_power = 0x1f, |
| 65 | // Eisel-Lemire | 65 | // Eisel-Lemire |
| 66 | .smallest_power_of_ten = -26, // TODO: refine, fails one test | 66 | .smallest_power_of_ten = -26, // TODO: refine, fails one test |
| ... | @@ -81,7 +81,7 @@ pub fn from(comptime T: type) Self { | ... | @@ -81,7 +81,7 @@ pub fn from(comptime T: type) Self { |
| 81 | .max_exponent_fast_path_disguised = 17, | 81 | .max_exponent_fast_path_disguised = 17, |
| 82 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), | 82 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), |
| 83 | // Slow + Eisel-Lemire | 83 | // Slow + Eisel-Lemire |
| 84 | .mantissa_explicit_bits = std.math.floatMantissaBits(T), | 84 | .mantissa_explicit_bits = std.math.floatFractionalBits(T), |
| 85 | .infinite_power = 0xff, | 85 | .infinite_power = 0xff, |
| 86 | // Eisel-Lemire | 86 | // Eisel-Lemire |
| 87 | .smallest_power_of_ten = -65, | 87 | .smallest_power_of_ten = -65, |
| ... | @@ -106,6 +106,26 @@ pub fn from(comptime T: type) Self { | ... | @@ -106,6 +106,26 @@ pub fn from(comptime T: type) Self { |
| 106 | .min_exponent_round_to_even = -4, | 106 | .min_exponent_round_to_even = -4, |
| 107 | .max_exponent_round_to_even = 23, | 107 | .max_exponent_round_to_even = 23, |
| 108 | }, | 108 | }, |
| 109 | f80 => .{ | ||
| 110 | // Fast-Path | ||
| 111 | .min_exponent_fast_path = -27, | ||
| 112 | .max_exponent_fast_path = 27, | ||
| 113 | .max_exponent_fast_path_disguised = 46, | ||
| 114 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), | ||
| 115 | // Slow + Eisel-Lemire | ||
| 116 | .mantissa_explicit_bits = std.math.floatFractionalBits(T), | ||
| 117 | .infinite_power = 0x7fff, | ||
| 118 | // Eisel-Lemire. | ||
| 119 | // NOTE: Not yet tested (no f80 eisel-lemire implementation) | ||
| 120 | .smallest_power_of_ten = -4966, | ||
| 121 | .largest_power_of_ten = 4932, | ||
| 122 | .minimum_exponent = -16382, | ||
| 123 | // 2^65 * 5^-q < 2^80 | ||
| 124 | // 5^-q < 2^15 | ||
| 125 | // => q >= -6 | ||
| 126 | .min_exponent_round_to_even = -6, | ||
| 127 | .max_exponent_round_to_even = 28, | ||
| 128 | }, | ||
| 109 | f128 => .{ | 129 | f128 => .{ |
| 110 | // Fast-Path | 130 | // Fast-Path |
| 111 | .min_exponent_fast_path = -48, | 131 | .min_exponent_fast_path = -48, |
| ... | @@ -113,7 +133,7 @@ pub fn from(comptime T: type) Self { | ... | @@ -113,7 +133,7 @@ pub fn from(comptime T: type) Self { |
| 113 | .max_exponent_fast_path_disguised = 82, | 133 | .max_exponent_fast_path_disguised = 82, |
| 114 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), | 134 | .max_mantissa_fast_path = 2 << std.math.floatMantissaBits(T), |
| 115 | // Slow + Eisel-Lemire | 135 | // Slow + Eisel-Lemire |
| 116 | .mantissa_explicit_bits = std.math.floatMantissaBits(T), | 136 | .mantissa_explicit_bits = std.math.floatFractionalBits(T), |
| 117 | .infinite_power = 0x7fff, | 137 | .infinite_power = 0x7fff, |
| 118 | // Eisel-Lemire. | 138 | // Eisel-Lemire. |
| 119 | // NOTE: Not yet tested (no f128 eisel-lemire implementation) | 139 | // NOTE: Not yet tested (no f128 eisel-lemire implementation) |
lib/std/fmt/parse_float/common.zig+7-2| ... | @@ -23,7 +23,11 @@ pub fn BiasedFp(comptime T: type) type { | ... | @@ -23,7 +23,11 @@ pub fn BiasedFp(comptime T: type) type { |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | pub fn inf(comptime FloatT: type) Self { | 25 | pub fn inf(comptime FloatT: type) Self { |
| 26 | return .{ .f = 0, .e = (1 << std.math.floatExponentBits(FloatT)) - 1 }; | 26 | const e = (1 << std.math.floatExponentBits(FloatT)) - 1; |
| 27 | return switch (FloatT) { | ||
| 28 | f80 => .{ .f = 0x8000000000000000, .e = e }, | ||
| 29 | else => .{ .f = 0, .e = e }, | ||
| 30 | }; | ||
| 27 | } | 31 | } |
| 28 | 32 | ||
| 29 | pub fn eql(self: Self, other: Self) bool { | 33 | pub fn eql(self: Self, other: Self) bool { |
| ... | @@ -45,6 +49,7 @@ pub fn floatFromUnsigned(comptime T: type, comptime MantissaT: type, v: Mantissa | ... | @@ -45,6 +49,7 @@ pub fn floatFromUnsigned(comptime T: type, comptime MantissaT: type, v: Mantissa |
| 45 | f16 => @as(f16, @bitCast(@as(u16, @truncate(v)))), | 49 | f16 => @as(f16, @bitCast(@as(u16, @truncate(v)))), |
| 46 | f32 => @as(f32, @bitCast(@as(u32, @truncate(v)))), | 50 | f32 => @as(f32, @bitCast(@as(u32, @truncate(v)))), |
| 47 | f64 => @as(f64, @bitCast(@as(u64, @truncate(v)))), | 51 | f64 => @as(f64, @bitCast(@as(u64, @truncate(v)))), |
| 52 | f80 => @as(f80, @bitCast(@as(u80, @truncate(v)))), | ||
| 48 | f128 => @as(f128, @bitCast(v)), | 53 | f128 => @as(f128, @bitCast(v)), |
| 49 | else => unreachable, | 54 | else => unreachable, |
| 50 | }; | 55 | }; |
| ... | @@ -85,7 +90,7 @@ pub fn isDigit(c: u8, comptime base: u8) bool { | ... | @@ -85,7 +90,7 @@ pub fn isDigit(c: u8, comptime base: u8) bool { |
| 85 | pub fn mantissaType(comptime T: type) type { | 90 | pub fn mantissaType(comptime T: type) type { |
| 86 | return switch (T) { | 91 | return switch (T) { |
| 87 | f16, f32, f64 => u64, | 92 | f16, f32, f64 => u64, |
| 88 | f128 => u128, | 93 | f80, f128 => u128, |
| 89 | else => unreachable, | 94 | else => unreachable, |
| 90 | }; | 95 | }; |
| 91 | } | 96 | } |
lib/std/fmt/parse_float/convert_fast.zig+7| ... | @@ -46,6 +46,13 @@ fn fastPow10(comptime T: type, i: usize) T { | ... | @@ -46,6 +46,13 @@ fn fastPow10(comptime T: type, i: usize) T { |
| 46 | 0, 0, 0, 0, 0, 0, 0, 0, | 46 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 47 | })[i & 31], | 47 | })[i & 31], |
| 48 | 48 | ||
| 49 | f80 => ([32]f80{ | ||
| 50 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, | ||
| 51 | 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, | ||
| 52 | 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, | ||
| 53 | 1e24, 1e25, 1e26, 1e27, 0, 0, 0, 0, | ||
| 54 | })[i & 31], | ||
| 55 | |||
| 49 | f128 => ([64]f128{ | 56 | f128 => ([64]f128{ |
| 50 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, | 57 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, |
| 51 | 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, | 58 | 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, |
lib/std/fmt/parse_float/convert_hex.zig+6-5| ... | @@ -25,11 +25,12 @@ pub fn convertHex(comptime T: type, n_: Number(T)) T { | ... | @@ -25,11 +25,12 @@ pub fn convertHex(comptime T: type, n_: Number(T)) T { |
| 25 | const max_exp = math.floatExponentMax(T); | 25 | const max_exp = math.floatExponentMax(T); |
| 26 | const min_exp = math.floatExponentMin(T); | 26 | const min_exp = math.floatExponentMin(T); |
| 27 | const mantissa_bits = math.floatMantissaBits(T); | 27 | const mantissa_bits = math.floatMantissaBits(T); |
| 28 | const fractional_bits = math.floatFractionalBits(T); | ||
| 28 | const exp_bits = math.floatExponentBits(T); | 29 | const exp_bits = math.floatExponentBits(T); |
| 29 | const exp_bias = min_exp - 1; | 30 | const exp_bias = min_exp - 1; |
| 30 | 31 | ||
| 31 | // mantissa now implicitly divided by 2^mantissa_bits | 32 | // mantissa now implicitly divided by 2^fractional_bits |
| 32 | n.exponent += mantissa_bits; | 33 | n.exponent += fractional_bits; |
| 33 | 34 | ||
| 34 | // Shift mantissa and exponent to bring representation into float range. | 35 | // Shift mantissa and exponent to bring representation into float range. |
| 35 | // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits. | 36 | // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits. |
| ... | @@ -44,7 +45,7 @@ pub fn convertHex(comptime T: type, n_: Number(T)) T { | ... | @@ -44,7 +45,7 @@ pub fn convertHex(comptime T: type, n_: Number(T)) T { |
| 44 | if (n.many_digits) { | 45 | if (n.many_digits) { |
| 45 | n.mantissa |= 1; | 46 | n.mantissa |= 1; |
| 46 | } | 47 | } |
| 47 | while (n.mantissa >> (1 + mantissa_bits + 2) != 0) { | 48 | while (n.mantissa >> (1 + fractional_bits + 2) != 0) { |
| 48 | n.mantissa = (n.mantissa >> 1) | (n.mantissa & 1); | 49 | n.mantissa = (n.mantissa >> 1) | (n.mantissa & 1); |
| 49 | n.exponent += 1; | 50 | n.exponent += 1; |
| 50 | } | 51 | } |
| ... | @@ -64,14 +65,14 @@ pub fn convertHex(comptime T: type, n_: Number(T)) T { | ... | @@ -64,14 +65,14 @@ pub fn convertHex(comptime T: type, n_: Number(T)) T { |
| 64 | n.exponent += 2; | 65 | n.exponent += 2; |
| 65 | if (round == 3) { | 66 | if (round == 3) { |
| 66 | n.mantissa += 1; | 67 | n.mantissa += 1; |
| 67 | if (n.mantissa == 1 << (1 + mantissa_bits)) { | 68 | if (n.mantissa == 1 << (1 + fractional_bits)) { |
| 68 | n.mantissa >>= 1; | 69 | n.mantissa >>= 1; |
| 69 | n.exponent += 1; | 70 | n.exponent += 1; |
| 70 | } | 71 | } |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | // Denormal or zero | 74 | // Denormal or zero |
| 74 | if (n.mantissa >> mantissa_bits == 0) { | 75 | if (n.mantissa >> fractional_bits == 0) { |
| 75 | n.exponent = exp_bias; | 76 | n.exponent = exp_bias; |
| 76 | } | 77 | } |
| 77 | 78 |
lib/std/fmt/parse_float/convert_slow.zig+6-6| ... | @@ -41,7 +41,7 @@ pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) { | ... | @@ -41,7 +41,7 @@ pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) { |
| 41 | const MantissaT = mantissaType(T); | 41 | const MantissaT = mantissaType(T); |
| 42 | const min_exponent = -(1 << (math.floatExponentBits(T) - 1)) + 1; | 42 | const min_exponent = -(1 << (math.floatExponentBits(T) - 1)) + 1; |
| 43 | const infinite_power = (1 << math.floatExponentBits(T)) - 1; | 43 | const infinite_power = (1 << math.floatExponentBits(T)) - 1; |
| 44 | const mantissa_explicit_bits = math.floatMantissaBits(T); | 44 | const fractional_bits = math.floatFractionalBits(T); |
| 45 | 45 | ||
| 46 | var d = Decimal(T).parse(s); // no need to recheck underscores | 46 | var d = Decimal(T).parse(s); // no need to recheck underscores |
| 47 | if (d.num_digits == 0 or d.decimal_point < Decimal(T).min_exponent) { | 47 | if (d.num_digits == 0 or d.decimal_point < Decimal(T).min_exponent) { |
| ... | @@ -97,9 +97,9 @@ pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) { | ... | @@ -97,9 +97,9 @@ pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) { |
| 97 | 97 | ||
| 98 | // Shift the decimal to the hidden bit, and then round the value | 98 | // Shift the decimal to the hidden bit, and then round the value |
| 99 | // to get the high mantissa+1 bits. | 99 | // to get the high mantissa+1 bits. |
| 100 | d.leftShift(mantissa_explicit_bits + 1); | 100 | d.leftShift(fractional_bits + 1); |
| 101 | var mantissa = d.round(); | 101 | var mantissa = d.round(); |
| 102 | if (mantissa >= (@as(MantissaT, 1) << (mantissa_explicit_bits + 1))) { | 102 | if (mantissa >= (@as(MantissaT, 1) << (fractional_bits + 1))) { |
| 103 | // Rounding up overflowed to the carry bit, need to | 103 | // Rounding up overflowed to the carry bit, need to |
| 104 | // shift back to the hidden bit. | 104 | // shift back to the hidden bit. |
| 105 | d.rightShift(1); | 105 | d.rightShift(1); |
| ... | @@ -110,10 +110,10 @@ pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) { | ... | @@ -110,10 +110,10 @@ pub fn convertSlow(comptime T: type, s: []const u8) BiasedFp(T) { |
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | var power2 = exp2 - min_exponent; | 112 | var power2 = exp2 - min_exponent; |
| 113 | if (mantissa < (@as(MantissaT, 1) << mantissa_explicit_bits)) { | 113 | if (mantissa < (@as(MantissaT, 1) << fractional_bits)) { |
| 114 | power2 -= 1; | 114 | power2 -= 1; |
| 115 | } | 115 | } |
| 116 | // Zero out all the bits above the explicit mantissa bits. | 116 | // Zero out all the bits above the mantissa bits. |
| 117 | mantissa &= (@as(MantissaT, 1) << mantissa_explicit_bits) - 1; | 117 | mantissa &= (@as(MantissaT, 1) << math.floatMantissaBits(T)) - 1; |
| 118 | return .{ .f = mantissa, .e = power2 }; | 118 | return .{ .f = mantissa, .e = power2 }; |
| 119 | } | 119 | } |