59 lines
1.9 KiB
Zig
59 lines
1.9 KiB
Zig
const builtin = @import("builtin");
|
|
const std = @import("std");
|
|
const maxInt = std.math.maxInt;
|
|
|
|
const significandBits = 23;
|
|
const exponentBias = 127;
|
|
const implicitBit = @as(u32, 1) << significandBits;
|
|
|
|
pub fn __floatunsisf(arg: u32) callconv(.C) f32 {
|
|
@setRuntimeSafety(builtin.is_test);
|
|
|
|
if (arg == 0) return 0.0;
|
|
|
|
// The exponent is the width of abs(a)
|
|
const exp = @as(u32, 31) - @clz(u32, arg);
|
|
|
|
var mantissa: u32 = undefined;
|
|
if (exp <= significandBits) {
|
|
// Shift a into the significand field and clear the implicit bit
|
|
const shift = @intCast(u5, significandBits - exp);
|
|
mantissa = @as(u32, arg) << shift ^ implicitBit;
|
|
} else {
|
|
const shift = @intCast(u5, exp - significandBits);
|
|
// Round to the nearest number after truncation
|
|
mantissa = @as(u32, arg) >> shift ^ implicitBit;
|
|
// Align to the left and check if the truncated part is halfway over
|
|
const round = arg << @intCast(u5, 31 - shift);
|
|
mantissa += @boolToInt(round > 0x80000000);
|
|
// Tie to even
|
|
mantissa += mantissa & 1;
|
|
}
|
|
|
|
// Use the addition instead of a or since we may have a carry from the
|
|
// mantissa to the exponent
|
|
var result = mantissa;
|
|
result += (exp + exponentBias) << significandBits;
|
|
|
|
return @bitCast(f32, result);
|
|
}
|
|
|
|
pub fn __aeabi_ui2f(arg: u32) callconv(.AAPCS) f32 {
|
|
@setRuntimeSafety(false);
|
|
return @call(.{ .modifier = .always_inline }, __floatunsisf, .{arg});
|
|
}
|
|
|
|
fn test_one_floatunsisf(a: u32, expected: u32) void {
|
|
const r = __floatunsisf(a);
|
|
std.testing.expect(@bitCast(u32, r) == expected);
|
|
}
|
|
|
|
test "floatunsisf" {
|
|
// Test the produced bit pattern
|
|
test_one_floatunsisf(0, 0);
|
|
test_one_floatunsisf(1, 0x3f800000);
|
|
test_one_floatunsisf(0x7FFFFFFF, 0x4f000000);
|
|
test_one_floatunsisf(0x80000000, 0x4f000000);
|
|
test_one_floatunsisf(0xFFFFFFFF, 0x4f800000);
|
|
}
|