trunc.zig (4509B) - Raw
1 //! Ported from musl, which is MIT licensed. 2 //! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT 3 //! 4 //! https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c 5 //! https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c 6 7 const std = @import("std"); 8 const builtin = @import("builtin"); 9 const arch = builtin.cpu.arch; 10 const math = std.math; 11 const mem = std.mem; 12 const expect = std.testing.expect; 13 const common = @import("common.zig"); 14 15 pub const panic = common.panic; 16 17 comptime { 18 @export(&__trunch, .{ .name = "__trunch", .linkage = common.linkage, .visibility = common.visibility }); 19 @export(&truncf, .{ .name = "truncf", .linkage = common.linkage, .visibility = common.visibility }); 20 @export(&trunc, .{ .name = "trunc", .linkage = common.linkage, .visibility = common.visibility }); 21 @export(&__truncx, .{ .name = "__truncx", .linkage = common.linkage, .visibility = common.visibility }); 22 if (common.want_ppc_abi) { 23 @export(&truncq, .{ .name = "truncf128", .linkage = common.linkage, .visibility = common.visibility }); 24 } 25 @export(&truncq, .{ .name = "truncq", .linkage = common.linkage, .visibility = common.visibility }); 26 @export(&truncl, .{ .name = "truncl", .linkage = common.linkage, .visibility = common.visibility }); 27 } 28 29 pub fn __trunch(x: f16) callconv(.c) f16 { 30 // TODO: more efficient implementation 31 return @floatCast(truncf(x)); 32 } 33 34 pub fn truncf(x: f32) callconv(.c) f32 { 35 const u: u32 = @bitCast(x); 36 var e = @as(i32, @intCast(((u >> 23) & 0xFF))) - 0x7F + 9; 37 var m: u32 = undefined; 38 39 if (e >= 23 + 9) { 40 return x; 41 } 42 if (e < 9) { 43 e = 1; 44 } 45 46 m = @as(u32, math.maxInt(u32)) >> @intCast(e); 47 if (u & m == 0) { 48 return x; 49 } else { 50 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120); 51 return @bitCast(u & ~m); 52 } 53 } 54 55 pub fn trunc(x: f64) callconv(.c) f64 { 56 const u: u64 = @bitCast(x); 57 var e = @as(i32, @intCast(((u >> 52) & 0x7FF))) - 0x3FF + 12; 58 var m: u64 = undefined; 59 60 if (e >= 52 + 12) { 61 return x; 62 } 63 if (e < 12) { 64 e = 1; 65 } 66 67 m = @as(u64, math.maxInt(u64)) >> @intCast(e); 68 if (u & m == 0) { 69 return x; 70 } else { 71 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120); 72 return @bitCast(u & ~m); 73 } 74 } 75 76 pub fn __truncx(x: f80) callconv(.c) f80 { 77 // TODO: more efficient implementation 78 return @floatCast(truncq(x)); 79 } 80 81 pub fn truncq(x: f128) callconv(.c) f128 { 82 const u: u128 = @bitCast(x); 83 var e = @as(i32, @intCast(((u >> 112) & 0x7FFF))) - 0x3FFF + 16; 84 var m: u128 = undefined; 85 86 if (e >= 112 + 16) { 87 return x; 88 } 89 if (e < 16) { 90 e = 1; 91 } 92 93 m = @as(u128, math.maxInt(u128)) >> @intCast(e); 94 if (u & m == 0) { 95 return x; 96 } else { 97 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120); 98 return @bitCast(u & ~m); 99 } 100 } 101 102 pub fn truncl(x: c_longdouble) callconv(.c) c_longdouble { 103 switch (@typeInfo(c_longdouble).float.bits) { 104 16 => return __trunch(x), 105 32 => return truncf(x), 106 64 => return trunc(x), 107 80 => return __truncx(x), 108 128 => return truncq(x), 109 else => @compileError("unreachable"), 110 } 111 } 112 113 test "trunc32" { 114 try expect(truncf(1.3) == 1.0); 115 try expect(truncf(-1.3) == -1.0); 116 try expect(truncf(0.2) == 0.0); 117 } 118 119 test "trunc64" { 120 try expect(trunc(1.3) == 1.0); 121 try expect(trunc(-1.3) == -1.0); 122 try expect(trunc(0.2) == 0.0); 123 } 124 125 test "trunc128" { 126 try expect(truncq(1.3) == 1.0); 127 try expect(truncq(-1.3) == -1.0); 128 try expect(truncq(0.2) == 0.0); 129 } 130 131 test "trunc32.special" { 132 try expect(truncf(0.0) == 0.0); // 0x3F800000 133 try expect(truncf(-0.0) == -0.0); 134 try expect(math.isPositiveInf(truncf(math.inf(f32)))); 135 try expect(math.isNegativeInf(truncf(-math.inf(f32)))); 136 try expect(math.isNan(truncf(math.nan(f32)))); 137 } 138 139 test "trunc64.special" { 140 try expect(trunc(0.0) == 0.0); 141 try expect(trunc(-0.0) == -0.0); 142 try expect(math.isPositiveInf(trunc(math.inf(f64)))); 143 try expect(math.isNegativeInf(trunc(-math.inf(f64)))); 144 try expect(math.isNan(trunc(math.nan(f64)))); 145 } 146 147 test "trunc128.special" { 148 try expect(truncq(0.0) == 0.0); 149 try expect(truncq(-0.0) == -0.0); 150 try expect(math.isPositiveInf(truncq(math.inf(f128)))); 151 try expect(math.isNegativeInf(truncq(-math.inf(f128)))); 152 try expect(math.isNan(truncq(math.nan(f128)))); 153 }