floor.zig (6290B) - Raw
1 //! Ported from musl, which is licensed under the MIT license: 2 //! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT 3 //! 4 //! https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c 5 //! https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c 6 7 const std = @import("std"); 8 const builtin = @import("builtin"); 9 const math = std.math; 10 const mem = std.mem; 11 const expect = std.testing.expect; 12 const arch = builtin.cpu.arch; 13 const common = @import("common.zig"); 14 15 pub const panic = common.panic; 16 17 comptime { 18 @export(&__floorh, .{ .name = "__floorh", .linkage = common.linkage, .visibility = common.visibility }); 19 @export(&floorf, .{ .name = "floorf", .linkage = common.linkage, .visibility = common.visibility }); 20 @export(&floor, .{ .name = "floor", .linkage = common.linkage, .visibility = common.visibility }); 21 @export(&__floorx, .{ .name = "__floorx", .linkage = common.linkage, .visibility = common.visibility }); 22 if (common.want_ppc_abi) { 23 @export(&floorq, .{ .name = "floorf128", .linkage = common.linkage, .visibility = common.visibility }); 24 } 25 @export(&floorq, .{ .name = "floorq", .linkage = common.linkage, .visibility = common.visibility }); 26 @export(&floorl, .{ .name = "floorl", .linkage = common.linkage, .visibility = common.visibility }); 27 } 28 29 pub fn __floorh(x: f16) callconv(.c) f16 { 30 var u: u16 = @bitCast(x); 31 const e = @as(i16, @intCast((u >> 10) & 31)) - 15; 32 var m: u16 = undefined; 33 34 // TODO: Shouldn't need this explicit check. 35 if (x == 0.0) { 36 return x; 37 } 38 39 if (e >= 10) { 40 return x; 41 } 42 43 if (e >= 0) { 44 m = @as(u16, 1023) >> @intCast(e); 45 if (u & m == 0) { 46 return x; 47 } 48 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); 49 if (u >> 15 != 0) { 50 u += m; 51 } 52 return @bitCast(u & ~m); 53 } else { 54 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); 55 if (u >> 15 == 0) { 56 return 0.0; 57 } else { 58 return -1.0; 59 } 60 } 61 } 62 63 pub fn floorf(x: f32) callconv(.c) f32 { 64 var u: u32 = @bitCast(x); 65 const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F; 66 var m: u32 = undefined; 67 68 // TODO: Shouldn't need this explicit check. 69 if (x == 0.0) { 70 return x; 71 } 72 73 if (e >= 23) { 74 return x; 75 } 76 77 if (e >= 0) { 78 m = @as(u32, 0x007FFFFF) >> @intCast(e); 79 if (u & m == 0) { 80 return x; 81 } 82 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); 83 if (u >> 31 != 0) { 84 u += m; 85 } 86 return @bitCast(u & ~m); 87 } else { 88 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); 89 if (u >> 31 == 0) { 90 return 0.0; 91 } else { 92 return -1.0; 93 } 94 } 95 } 96 97 pub fn floor(x: f64) callconv(.c) f64 { 98 const f64_toint = 1.0 / math.floatEps(f64); 99 100 const u: u64 = @bitCast(x); 101 const e = (u >> 52) & 0x7FF; 102 var y: f64 = undefined; 103 104 if (e >= 0x3FF + 52 or x == 0) { 105 return x; 106 } 107 108 if (u >> 63 != 0) { 109 y = x - f64_toint + f64_toint - x; 110 } else { 111 y = x + f64_toint - f64_toint - x; 112 } 113 114 if (e <= 0x3FF - 1) { 115 if (common.want_float_exceptions) mem.doNotOptimizeAway(y); 116 if (u >> 63 != 0) { 117 return -1.0; 118 } else { 119 return 0.0; 120 } 121 } else if (y > 0) { 122 return x + y - 1; 123 } else { 124 return x + y; 125 } 126 } 127 128 pub fn __floorx(x: f80) callconv(.c) f80 { 129 // TODO: more efficient implementation 130 return @floatCast(floorq(x)); 131 } 132 133 pub fn floorq(x: f128) callconv(.c) f128 { 134 const f128_toint = 1.0 / math.floatEps(f128); 135 136 const u: u128 = @bitCast(x); 137 const e = (u >> 112) & 0x7FFF; 138 var y: f128 = undefined; 139 140 if (e >= 0x3FFF + 112 or x == 0) return x; 141 142 if (u >> 127 != 0) { 143 y = x - f128_toint + f128_toint - x; 144 } else { 145 y = x + f128_toint - f128_toint - x; 146 } 147 148 if (e <= 0x3FFF - 1) { 149 if (common.want_float_exceptions) mem.doNotOptimizeAway(y); 150 if (u >> 127 != 0) { 151 return -1.0; 152 } else { 153 return 0.0; 154 } 155 } else if (y > 0) { 156 return x + y - 1; 157 } else { 158 return x + y; 159 } 160 } 161 162 pub fn floorl(x: c_longdouble) callconv(.c) c_longdouble { 163 switch (@typeInfo(c_longdouble).float.bits) { 164 16 => return __floorh(x), 165 32 => return floorf(x), 166 64 => return floor(x), 167 80 => return __floorx(x), 168 128 => return floorq(x), 169 else => @compileError("unreachable"), 170 } 171 } 172 173 test "floor16" { 174 try expect(__floorh(1.3) == 1.0); 175 try expect(__floorh(-1.3) == -2.0); 176 try expect(__floorh(0.2) == 0.0); 177 } 178 179 test "floor32" { 180 try expect(floorf(1.3) == 1.0); 181 try expect(floorf(-1.3) == -2.0); 182 try expect(floorf(0.2) == 0.0); 183 } 184 185 test "floor64" { 186 try expect(floor(1.3) == 1.0); 187 try expect(floor(-1.3) == -2.0); 188 try expect(floor(0.2) == 0.0); 189 } 190 191 test "floor128" { 192 try expect(floorq(1.3) == 1.0); 193 try expect(floorq(-1.3) == -2.0); 194 try expect(floorq(0.2) == 0.0); 195 } 196 197 test "floor16.special" { 198 try expect(__floorh(0.0) == 0.0); 199 try expect(__floorh(-0.0) == -0.0); 200 try expect(math.isPositiveInf(__floorh(math.inf(f16)))); 201 try expect(math.isNegativeInf(__floorh(-math.inf(f16)))); 202 try expect(math.isNan(__floorh(math.nan(f16)))); 203 } 204 205 test "floor32.special" { 206 try expect(floorf(0.0) == 0.0); 207 try expect(floorf(-0.0) == -0.0); 208 try expect(math.isPositiveInf(floorf(math.inf(f32)))); 209 try expect(math.isNegativeInf(floorf(-math.inf(f32)))); 210 try expect(math.isNan(floorf(math.nan(f32)))); 211 } 212 213 test "floor64.special" { 214 try expect(floor(0.0) == 0.0); 215 try expect(floor(-0.0) == -0.0); 216 try expect(math.isPositiveInf(floor(math.inf(f64)))); 217 try expect(math.isNegativeInf(floor(-math.inf(f64)))); 218 try expect(math.isNan(floor(math.nan(f64)))); 219 } 220 221 test "floor128.special" { 222 try expect(floorq(0.0) == 0.0); 223 try expect(floorq(-0.0) == -0.0); 224 try expect(math.isPositiveInf(floorq(math.inf(f128)))); 225 try expect(math.isNegativeInf(floorq(-math.inf(f128)))); 226 try expect(math.isNan(floorq(math.nan(f128)))); 227 }