|
| 1 | +const builtin = @import("builtin"); |
| 2 | +const std = @import("std"); |
| 3 | +const maxInt = std.math.maxInt; |
| 4 | + |
| 5 | +const FLT_MANT_DIG = 24; |
| 6 | + |
| 7 | +pub extern fn __floatundisf(arg: u64) f32 { |
| 8 | + @setRuntimeSafety(builtin.is_test); |
| 9 | + |
| 10 | + if (arg == 0) return 0; |
| 11 | + |
| 12 | + var a = arg; |
| 13 | + const N: usize = @TypeOf(a).bit_count; |
| 14 | + // Number of significant digits |
| 15 | + const sd = N - @clz(u64, a); |
| 16 | + // 8 exponent |
| 17 | + var e = @intCast(u32, sd) - 1; |
| 18 | + |
| 19 | + if (sd > FLT_MANT_DIG) { |
| 20 | + // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx |
| 21 | + // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR |
| 22 | + // 12345678901234567890123456 |
| 23 | + // 1 = msb 1 bit |
| 24 | + // P = bit FLT_MANT_DIG-1 bits to the right of 1 |
| 25 | + // Q = bit FLT_MANT_DIG bits to the right of 1 |
| 26 | + // R = "or" of all bits to the right of Q |
| 27 | + switch (sd) { |
| 28 | + FLT_MANT_DIG + 1 => a <<= 1, |
| 29 | + FLT_MANT_DIG + 2 => {}, |
| 30 | + else => { |
| 31 | + const shift_amt = @intCast(u6, ((N + FLT_MANT_DIG + 2) - sd)); |
| 32 | + const all_ones: u64 = maxInt(u64); |
| 33 | + a = (a >> @intCast(u6, sd - (FLT_MANT_DIG + 2))) | |
| 34 | + @boolToInt(a & (all_ones >> shift_amt) != 0); |
| 35 | + }, |
| 36 | + } |
| 37 | + // Or P into R |
| 38 | + a |= @boolToInt((a & 4) != 0); |
| 39 | + // round - this step may add a significant bit |
| 40 | + a += 1; |
| 41 | + // dump Q and R |
| 42 | + a >>= 2; |
| 43 | + // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits |
| 44 | + if ((a & (@as(u64, 1) << FLT_MANT_DIG)) != 0) { |
| 45 | + a >>= 1; |
| 46 | + e += 1; |
| 47 | + } |
| 48 | + // a is now rounded to FLT_MANT_DIG bits |
| 49 | + } else { |
| 50 | + a <<= @intCast(u6, FLT_MANT_DIG - sd); |
| 51 | + // a is now rounded to FLT_MANT_DIG bits |
| 52 | + } |
| 53 | + |
| 54 | + const result: u32 = ((e + 127) << 23) | // exponent |
| 55 | + @truncate(u32, a & 0x007FFFFF); // mantissa |
| 56 | + return @bitCast(f32, result); |
| 57 | +} |
| 58 | + |
| 59 | +fn test__floatundisf(a: u64, expected: f32) void { |
| 60 | + std.testing.expectEqual(expected, __floatundisf(a)); |
| 61 | +} |
| 62 | + |
| 63 | +test "floatundisf" { |
| 64 | + test__floatundisf(0, 0.0); |
| 65 | + test__floatundisf(1, 1.0); |
| 66 | + test__floatundisf(2, 2.0); |
| 67 | + test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62F); |
| 68 | + test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62F); |
| 69 | + test__floatundisf(0x8000008000000000, 0x1p+63F); |
| 70 | + test__floatundisf(0x8000010000000000, 0x1.000002p+63F); |
| 71 | + test__floatundisf(0x8000000000000000, 0x1p+63F); |
| 72 | + test__floatundisf(0x8000000000000001, 0x1p+63F); |
| 73 | + test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64F); |
| 74 | + test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64F); |
| 75 | + test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50F); |
| 76 | + test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50F); |
| 77 | + test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50F); |
| 78 | + test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50F); |
| 79 | + test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50F); |
| 80 | + test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50F); |
| 81 | + test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50F); |
| 82 | + test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50F); |
| 83 | + test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50F); |
| 84 | + test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50F); |
| 85 | + test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50F); |
| 86 | +} |
0 commit comments