blob d6761ba7 (5452B) - 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 expect = std.testing.expect; 8 const std = @import("../std.zig"); 9 const math = std.math; 10 11 /// Returns the greatest integer value less than or equal to x. 12 /// 13 /// Special Cases: 14 /// - floor(+-0) = +-0 15 /// - floor(+-inf) = +-inf 16 /// - floor(nan) = nan 17 pub fn floor(x: anytype) @TypeOf(x) { 18 const T = @TypeOf(x); 19 return switch (T) { 20 f16 => floor16(x), 21 f32 => floor32(x), 22 f64 => floor64(x), 23 f128 => floor128(x), 24 25 // TODO this is not correct for some targets 26 c_longdouble => @floatCast(c_longdouble, floor128(x)), 27 28 else => @compileError("floor not implemented for " ++ @typeName(T)), 29 }; 30 } 31 32 fn floor16(x: f16) f16 { 33 var u = @bitCast(u16, x); 34 const e = @intCast(i16, (u >> 10) & 31) - 15; 35 var m: u16 = undefined; 36 37 // TODO: Shouldn't need this explicit check. 38 if (x == 0.0) { 39 return x; 40 } 41 42 if (e >= 10) { 43 return x; 44 } 45 46 if (e >= 0) { 47 m = @as(u16, 1023) >> @intCast(u4, e); 48 if (u & m == 0) { 49 return x; 50 } 51 math.doNotOptimizeAway(x + 0x1.0p120); 52 if (u >> 15 != 0) { 53 u += m; 54 } 55 return @bitCast(f16, u & ~m); 56 } else { 57 math.doNotOptimizeAway(x + 0x1.0p120); 58 if (u >> 15 == 0) { 59 return 0.0; 60 } else { 61 return -1.0; 62 } 63 } 64 } 65 66 fn floor32(x: f32) f32 { 67 var u = @bitCast(u32, x); 68 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F; 69 var m: u32 = undefined; 70 71 // TODO: Shouldn't need this explicit check. 72 if (x == 0.0) { 73 return x; 74 } 75 76 if (e >= 23) { 77 return x; 78 } 79 80 if (e >= 0) { 81 m = @as(u32, 0x007FFFFF) >> @intCast(u5, e); 82 if (u & m == 0) { 83 return x; 84 } 85 math.doNotOptimizeAway(x + 0x1.0p120); 86 if (u >> 31 != 0) { 87 u += m; 88 } 89 return @bitCast(f32, u & ~m); 90 } else { 91 math.doNotOptimizeAway(x + 0x1.0p120); 92 if (u >> 31 == 0) { 93 return 0.0; 94 } else { 95 return -1.0; 96 } 97 } 98 } 99 100 fn floor64(x: f64) f64 { 101 const u = @bitCast(u64, x); 102 const e = (u >> 52) & 0x7FF; 103 var y: f64 = undefined; 104 105 if (e >= 0x3FF + 52 or x == 0) { 106 return x; 107 } 108 109 if (u >> 63 != 0) { 110 y = x - math.f64_toint + math.f64_toint - x; 111 } else { 112 y = x + math.f64_toint - math.f64_toint - x; 113 } 114 115 if (e <= 0x3FF - 1) { 116 math.doNotOptimizeAway(y); 117 if (u >> 63 != 0) { 118 return -1.0; 119 } else { 120 return 0.0; 121 } 122 } else if (y > 0) { 123 return x + y - 1; 124 } else { 125 return x + y; 126 } 127 } 128 129 fn floor128(x: f128) f128 { 130 const u = @bitCast(u128, x); 131 const e = (u >> 112) & 0x7FFF; 132 var y: f128 = undefined; 133 134 if (e >= 0x3FFF + 112 or x == 0) return x; 135 136 if (u >> 127 != 0) { 137 y = x - math.f128_toint + math.f128_toint - x; 138 } else { 139 y = x + math.f128_toint - math.f128_toint - x; 140 } 141 142 if (e <= 0x3FFF - 1) { 143 math.doNotOptimizeAway(y); 144 if (u >> 127 != 0) { 145 return -1.0; 146 } else { 147 return 0.0; 148 } 149 } else if (y > 0) { 150 return x + y - 1; 151 } else { 152 return x + y; 153 } 154 } 155 156 test "math.floor" { 157 try expect(floor(@as(f16, 1.3)) == floor16(1.3)); 158 try expect(floor(@as(f32, 1.3)) == floor32(1.3)); 159 try expect(floor(@as(f64, 1.3)) == floor64(1.3)); 160 try expect(floor(@as(f128, 1.3)) == floor128(1.3)); 161 } 162 163 test "math.floor16" { 164 try expect(floor16(1.3) == 1.0); 165 try expect(floor16(-1.3) == -2.0); 166 try expect(floor16(0.2) == 0.0); 167 } 168 169 test "math.floor32" { 170 try expect(floor32(1.3) == 1.0); 171 try expect(floor32(-1.3) == -2.0); 172 try expect(floor32(0.2) == 0.0); 173 } 174 175 test "math.floor64" { 176 try expect(floor64(1.3) == 1.0); 177 try expect(floor64(-1.3) == -2.0); 178 try expect(floor64(0.2) == 0.0); 179 } 180 181 test "math.floor128" { 182 try expect(floor128(1.3) == 1.0); 183 try expect(floor128(-1.3) == -2.0); 184 try expect(floor128(0.2) == 0.0); 185 } 186 187 test "math.floor16.special" { 188 try expect(floor16(0.0) == 0.0); 189 try expect(floor16(-0.0) == -0.0); 190 try expect(math.isPositiveInf(floor16(math.inf(f16)))); 191 try expect(math.isNegativeInf(floor16(-math.inf(f16)))); 192 try expect(math.isNan(floor16(math.nan(f16)))); 193 } 194 195 test "math.floor32.special" { 196 try expect(floor32(0.0) == 0.0); 197 try expect(floor32(-0.0) == -0.0); 198 try expect(math.isPositiveInf(floor32(math.inf(f32)))); 199 try expect(math.isNegativeInf(floor32(-math.inf(f32)))); 200 try expect(math.isNan(floor32(math.nan(f32)))); 201 } 202 203 test "math.floor64.special" { 204 try expect(floor64(0.0) == 0.0); 205 try expect(floor64(-0.0) == -0.0); 206 try expect(math.isPositiveInf(floor64(math.inf(f64)))); 207 try expect(math.isNegativeInf(floor64(-math.inf(f64)))); 208 try expect(math.isNan(floor64(math.nan(f64)))); 209 } 210 211 test "math.floor128.special" { 212 try expect(floor128(0.0) == 0.0); 213 try expect(floor128(-0.0) == -0.0); 214 try expect(math.isPositiveInf(floor128(math.inf(f128)))); 215 try expect(math.isNegativeInf(floor128(-math.inf(f128)))); 216 try expect(math.isNan(floor128(math.nan(f128)))); 217 }