| ... | @@ -4,29 +4,21 @@ const expect = std.testing.expect; | ... | @@ -4,29 +4,21 @@ const expect = std.testing.expect; |
| 4 | | 4 | |
| 5 | /// Creates a raw "1.0" mantissa for floating point type T. Used to dedupe f80 logic. | 5 | /// Creates a raw "1.0" mantissa for floating point type T. Used to dedupe f80 logic. |
| 6 | inline fn mantissaOne(comptime T: type) comptime_int { | 6 | inline fn mantissaOne(comptime T: type) comptime_int { |
| 7 | return 1 << floatFractionalBits(T) & ((1 << floatMantissaBits(T)) - 1); | 7 | return if (@typeInfo(T).Float.bits == 80) 1 << floatFractionalBits(T) else 0; |
| 8 | } | 8 | } |
| 9 | | 9 | |
| 10 | /// Creates floating point type T from an unbiased exponent and raw mantissa. | 10 | /// Creates floating point type T from an unbiased exponent and raw mantissa. |
| 11 | inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T { | 11 | inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T { |
| 12 | const FBits = @Type(.{ .Float = .{ .bits = floatBits(T) } }); | 12 | const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); |
| 13 | const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = floatBits(T) } }); | | |
| 14 | const biased_exponent = @as(TBits, exponent + floatExponentMax(T)); | 13 | const biased_exponent = @as(TBits, exponent + floatExponentMax(T)); |
| 15 | return @bitCast(FBits, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)); | 14 | return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)); |
| 16 | } | | |
| 17 | | | |
| 18 | /// Returns the number of bits in floating point type T. | | |
| 19 | pub inline fn floatBits(comptime T: type) comptime_int { | | |
| 20 | return switch (@typeInfo(T)) { | | |
| 21 | .Float => |info| info.bits, | | |
| 22 | .ComptimeFloat => 128, | | |
| 23 | else => @compileError(@typeName(T) ++ " is not a floating point type"), | | |
| 24 | }; | | |
| 25 | } | 15 | } |
| 26 | | 16 | |
| 27 | /// Returns the number of bits in the exponent of floating point type T. | 17 | /// Returns the number of bits in the exponent of floating point type T. |
| 28 | pub inline fn floatExponentBits(comptime T: type) comptime_int { | 18 | pub inline fn floatExponentBits(comptime T: type) comptime_int { |
| 29 | return switch (floatBits(T)) { | 19 | comptime assert(@typeInfo(T) == .Float); |
| | 20 | |
| | 21 | return switch (@typeInfo(T).Float.bits) { |
| 30 | 16 => 5, | 22 | 16 => 5, |
| 31 | 32 => 8, | 23 | 32 => 8, |
| 32 | 64 => 11, | 24 | 64 => 11, |
| ... | @@ -38,7 +30,9 @@ pub inline fn floatExponentBits(comptime T: type) comptime_int { | ... | @@ -38,7 +30,9 @@ pub inline fn floatExponentBits(comptime T: type) comptime_int { |
| 38 | | 30 | |
| 39 | /// Returns the number of bits in the mantissa of floating point type T. | 31 | /// Returns the number of bits in the mantissa of floating point type T. |
| 40 | pub inline fn floatMantissaBits(comptime T: type) comptime_int { | 32 | pub inline fn floatMantissaBits(comptime T: type) comptime_int { |
| 41 | return switch (floatBits(T)) { | 33 | comptime assert(@typeInfo(T) == .Float); |
| | 34 | |
| | 35 | return switch (@typeInfo(T).Float.bits) { |
| 42 | 16 => 10, | 36 | 16 => 10, |
| 43 | 32 => 23, | 37 | 32 => 23, |
| 44 | 64 => 52, | 38 | 64 => 52, |
| ... | @@ -50,10 +44,12 @@ pub inline fn floatMantissaBits(comptime T: type) comptime_int { | ... | @@ -50,10 +44,12 @@ pub inline fn floatMantissaBits(comptime T: type) comptime_int { |
| 50 | | 44 | |
| 51 | /// Returns the number of fractional bits in the mantissa of floating point type T. | 45 | /// Returns the number of fractional bits in the mantissa of floating point type T. |
| 52 | pub inline fn floatFractionalBits(comptime T: type) comptime_int { | 46 | pub inline fn floatFractionalBits(comptime T: type) comptime_int { |
| | 47 | comptime assert(@typeInfo(T) == .Float); |
| | 48 | |
| 53 | // standard IEEE floats have an implicit 0.m or 1.m integer part | 49 | // standard IEEE floats have an implicit 0.m or 1.m integer part |
| 54 | // f80 is special and has an explicitly stored bit in the MSB | 50 | // f80 is special and has an explicitly stored bit in the MSB |
| 55 | // this function corresponds to `MANT_DIG - 1' from C | 51 | // this function corresponds to `MANT_DIG - 1' from C |
| 56 | return switch (floatBits(T)) { | 52 | return switch (@typeInfo(T).Float.bits) { |
| 57 | 16 => 10, | 53 | 16 => 10, |
| 58 | 32 => 23, | 54 | 32 => 23, |
| 59 | 64 => 52, | 55 | 64 => 52, |
| ... | @@ -105,7 +101,6 @@ test "float bits" { | ... | @@ -105,7 +101,6 @@ test "float bits" { |
| 105 | inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { | 101 | inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { |
| 106 | // (1 +) for the sign bit, since it is separate from the other bits | 102 | // (1 +) for the sign bit, since it is separate from the other bits |
| 107 | const size = 1 + floatExponentBits(T) + floatMantissaBits(T); | 103 | const size = 1 + floatExponentBits(T) + floatMantissaBits(T); |
| 108 | try expect(floatBits(T) == size); | | |
| 109 | try expect(@bitSizeOf(T) == size); | 104 | try expect(@bitSizeOf(T) == size); |
| 110 | | 105 | |
| 111 | // for machine epsilon, assert expmin <= -prec <= expmax | 106 | // for machine epsilon, assert expmin <= -prec <= expmax |