authorgravatar for hmccarty@pm.meHarrison McCarty <hmccarty@pm.me> 2024-06-30 04:12:52-07:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2024-07-14 11:19:34+12:00
log8ff01f78f314a743df8c8f085a02416bb1ce0c72
tree052e28d9141c7d4a04c7680beedd34d6b04f91f5
parent959d227d1370c9cf9198ed111e3a8bca15a7e47b

std.fmt.parseFloat: add f80 formatFloat support


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);
15231523
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);
15271526
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}
15351533
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 }
2323
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.
7672
77test parseFloat {73test 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}
132128
133test "nan and inf" {129test "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);
136132
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}
149146
...@@ -152,8 +149,8 @@ test "#11169" {...@@ -152,8 +149,8 @@ test "#11169" {
152}149}
153150
154test "many_digits hex" {151test "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}
159156
...@@ -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
166test "hex.zero" {164test "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
223test "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
224test "hex.f128" {239test "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-even253 // 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-Lemire62 // 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-Lemire65 // Eisel-Lemire
66 .smallest_power_of_ten = -26, // TODO: refine, fails one test66 .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-Lemire83 // 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-Lemire86 // 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-Path130 // 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-Lemire135 // 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 }
2424
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 }
2832
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 {
85pub fn mantissaType(comptime T: type) type {90pub 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],
4848
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;
3031
31 // mantissa now implicitly divided by 2^mantissa_bits32 // mantissa now implicitly divided by 2^fractional_bits
32 n.exponent += mantissa_bits;33 n.exponent += fractional_bits;
3334
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 }
7273
73 // Denormal or zero74 // 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 }
7778
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);
4545
46 var d = Decimal(T).parse(s); // no need to recheck underscores46 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) {
9797
98 // Shift the decimal to the hidden bit, and then round the value98 // 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 to103 // 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}