| ... | ... | @@ -0,0 +1,90 @@ |
| 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std"); |
| 3 | const maxInt = std.math.maxInt; |
| 4 | |
| 5 | fn floatsiXf(comptime T: type, a: i32) T { |
| 6 | @setRuntimeSafety(builtin.is_test); |
| 7 | |
| 8 | const Z = @IntType(false, T.bit_count); |
| 9 | const S = @IntType(false, T.bit_count - @clz(Z(T.bit_count) - 1)); |
| 10 | |
| 11 | if (a == 0) { |
| 12 | return T(0.0); |
| 13 | } |
| 14 | |
| 15 | const significandBits = std.math.floatMantissaBits(T); |
| 16 | const exponentBits = std.math.floatExponentBits(T); |
| 17 | const exponentBias = ((1 << exponentBits - 1) - 1); |
| 18 | |
| 19 | const implicitBit = Z(1) << significandBits; |
| 20 | const signBit = Z(1 << Z.bit_count - 1); |
| 21 | |
| 22 | const sign = a >> 31; |
| 23 | // Take absolute value of a via abs(x) = (x^(x >> 31)) - (x >> 31). |
| 24 | const abs_a = (a ^ sign) -% sign; |
| 25 | // The exponent is the width of abs(a) |
| 26 | const exp = Z(31 - @clz(abs_a)); |
| 27 | |
| 28 | const sign_bit = if (sign < 0) signBit else 0; |
| 29 | |
| 30 | var mantissa: Z = undefined; |
| 31 | // Shift a into the significand field and clear the implicit bit. |
| 32 | if (exp <= significandBits) { |
| 33 | // No rounding needed |
| 34 | const shift = @intCast(S, significandBits - exp); |
| 35 | mantissa = @intCast(Z, @bitCast(u32, abs_a)) << shift ^ implicitBit; |
| 36 | } else { |
| 37 | const shift = @intCast(S, exp - significandBits); |
| 38 | // Round to the nearest number after truncation |
| 39 | mantissa = @intCast(Z, @bitCast(u32, abs_a)) >> shift ^ implicitBit; |
| 40 | // Align to the left and check if the truncated part is halfway over |
| 41 | const round = @bitCast(u32, abs_a) << @intCast(u5, 31 - shift); |
| 42 | mantissa += @boolToInt(round > 0x80000000); |
| 43 | // Tie to even |
| 44 | mantissa += mantissa & 1; |
| 45 | } |
| 46 | |
| 47 | // Use the addition instead of a or since we may have a carry from the |
| 48 | // mantissa to the exponent |
| 49 | var result = mantissa; |
| 50 | result += (exp + exponentBias) << significandBits; |
| 51 | result += sign_bit; |
| 52 | |
| 53 | return @bitCast(T, result); |
| 54 | } |
| 55 | |
| 56 | pub extern fn __floatsisf(arg: i32) f32 { |
| 57 | @setRuntimeSafety(builtin.is_test); |
| 58 | return @inlineCall(floatsiXf, f32, arg); |
| 59 | } |
| 60 | |
| 61 | pub extern fn __floatsidf(arg: i32) f64 { |
| 62 | @setRuntimeSafety(builtin.is_test); |
| 63 | return @inlineCall(floatsiXf, f64, arg); |
| 64 | } |
| 65 | |
| 66 | fn test_one_floatsidf(a: i32, expected: u64) void { |
| 67 | const r = __floatsidf(a); |
| 68 | std.testing.expect(@bitCast(u64, r) == expected); |
| 69 | } |
| 70 | |
| 71 | fn test_one_floatsisf(a: i32, expected: u32) void { |
| 72 | const r = __floatsisf(a); |
| 73 | std.testing.expect(@bitCast(u32, r) == expected); |
| 74 | } |
| 75 | |
| 76 | test "floatsidf" { |
| 77 | test_one_floatsidf(0, 0x0000000000000000); |
| 78 | test_one_floatsidf(1, 0x3ff0000000000000); |
| 79 | test_one_floatsidf(-1, 0xbff0000000000000); |
| 80 | test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); |
| 81 | test_one_floatsidf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xc1e0000000000000); |
| 82 | } |
| 83 | |
| 84 | test "floatsisf" { |
| 85 | test_one_floatsisf(0, 0x00000000); |
| 86 | test_one_floatsisf(1, 0x3f800000); |
| 87 | test_one_floatsisf(-1, 0xbf800000); |
| 88 | test_one_floatsisf(0x7FFFFFFF, 0x4f000000); |
| 89 | test_one_floatsisf(@bitCast(i32, @intCast(u32, 0x80000000)), 0xcf000000); |
| 90 | } |