| author | |
| committer | |
| log | 99323a4da1617ba8fcf74656004dd5ad8d90dae1 |
| tree | 6b2b641ebc5915dee34ff35dbfbb079a708b8d0a |
| parent | 91b0adc4c15a273b7a8a94371941a3f3f7fd2232 |
2 files changed, 129 insertions(+), 63 deletions(-)
lib/compiler_rt/ceil.zig+77-22| ... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
| 3 | //! | 3 | //! |
| 4 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c | 4 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c |
| 5 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c | 5 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c |
| 6 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/ceill.c | ||
| 6 | 7 | ||
| 7 | const std = @import("std"); | 8 | const std = @import("std"); |
| 8 | const builtin = @import("builtin"); | 9 | const builtin = @import("builtin"); |
| ... | @@ -27,8 +28,23 @@ comptime { | ... | @@ -27,8 +28,23 @@ comptime { |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | pub fn __ceilh(x: f16) callconv(.c) f16 { | 30 | pub fn __ceilh(x: f16) callconv(.c) f16 { |
| 30 | // TODO: more efficient implementation | 31 | var u: u16 = @bitCast(x); |
| 31 | return @floatCast(ceilf(x)); | 32 | const e = @as(i16, @intCast((u >> 10) & 31)) - 15; |
| 33 | var m: u16 = undefined; | ||
| 34 | |||
| 35 | if (e >= 10) return x; | ||
| 36 | |||
| 37 | if (e >= 0) { | ||
| 38 | m = @as(u16, 0x03FF) >> @intCast(e); | ||
| 39 | if (u & m == 0) return x; | ||
| 40 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | ||
| 41 | if (u >> 15 == 0) u += m; | ||
| 42 | u &= ~m; | ||
| 43 | return @bitCast(u); | ||
| 44 | } else { | ||
| 45 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | ||
| 46 | return if (u >> 15 != 0) -0.0 else if (u << 1 != 0) 1.0 else x; | ||
| 47 | } | ||
| 32 | } | 48 | } |
| 33 | 49 | ||
| 34 | pub fn ceilf(x: f32) callconv(.c) f32 { | 50 | pub fn ceilf(x: f32) callconv(.c) f32 { |
| ... | @@ -36,31 +52,18 @@ pub fn ceilf(x: f32) callconv(.c) f32 { | ... | @@ -36,31 +52,18 @@ pub fn ceilf(x: f32) callconv(.c) f32 { |
| 36 | const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F; | 52 | const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F; |
| 37 | var m: u32 = undefined; | 53 | var m: u32 = undefined; |
| 38 | 54 | ||
| 39 | // TODO: Shouldn't need this explicit check. | 55 | if (e >= 23) return x; |
| 40 | if (x == 0.0) { | ||
| 41 | return x; | ||
| 42 | } | ||
| 43 | 56 | ||
| 44 | if (e >= 23) { | 57 | if (e >= 0) { |
| 45 | return x; | ||
| 46 | } else if (e >= 0) { | ||
| 47 | m = @as(u32, 0x007FFFFF) >> @intCast(e); | 58 | m = @as(u32, 0x007FFFFF) >> @intCast(e); |
| 48 | if (u & m == 0) { | 59 | if (u & m == 0) return x; |
| 49 | return x; | ||
| 50 | } | ||
| 51 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | 60 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); |
| 52 | if (u >> 31 == 0) { | 61 | if (u >> 31 == 0) u += m; |
| 53 | u += m; | ||
| 54 | } | ||
| 55 | u &= ~m; | 62 | u &= ~m; |
| 56 | return @bitCast(u); | 63 | return @bitCast(u); |
| 57 | } else { | 64 | } else { |
| 58 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | 65 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); |
| 59 | if (u >> 31 != 0) { | 66 | return if (u >> 31 != 0) -0.0 else if (u << 1 != 0) 1.0 else x; |
| 60 | return -0.0; | ||
| 61 | } else { | ||
| 62 | return 1.0; | ||
| 63 | } | ||
| 64 | } | 67 | } |
| 65 | } | 68 | } |
| 66 | 69 | ||
| ... | @@ -96,8 +99,32 @@ pub fn ceil(x: f64) callconv(.c) f64 { | ... | @@ -96,8 +99,32 @@ pub fn ceil(x: f64) callconv(.c) f64 { |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | pub fn __ceilx(x: f80) callconv(.c) f80 { | 101 | pub fn __ceilx(x: f80) callconv(.c) f80 { |
| 99 | // TODO: more efficient implementation | 102 | const f80_toint = 1.0 / math.floatEps(f80); |
| 100 | return @floatCast(ceilq(x)); | 103 | |
| 104 | const u: u80 = @bitCast(x); | ||
| 105 | const e = (u >> 64) & 0x7FFF; | ||
| 106 | var y: f80 = undefined; | ||
| 107 | |||
| 108 | if (e >= 0x3FFF + 64 or x == 0) return x; | ||
| 109 | |||
| 110 | if (u >> 79 != 0) { | ||
| 111 | y = x - f80_toint + f80_toint - x; | ||
| 112 | } else { | ||
| 113 | y = x + f80_toint - f80_toint - x; | ||
| 114 | } | ||
| 115 | |||
| 116 | if (e <= 0x3FFF - 1) { | ||
| 117 | if (common.want_float_exceptions) mem.doNotOptimizeAway(y); | ||
| 118 | if (u >> 79 != 0) { | ||
| 119 | return -0.0; | ||
| 120 | } else { | ||
| 121 | return 1.0; | ||
| 122 | } | ||
| 123 | } else if (y < 0) { | ||
| 124 | return x + y + 1; | ||
| 125 | } else { | ||
| 126 | return x + y; | ||
| 127 | } | ||
| 101 | } | 128 | } |
| 102 | 129 | ||
| 103 | pub fn ceilq(x: f128) callconv(.c) f128 { | 130 | pub fn ceilq(x: f128) callconv(.c) f128 { |
| ... | @@ -140,6 +167,12 @@ pub fn ceill(x: c_longdouble) callconv(.c) c_longdouble { | ... | @@ -140,6 +167,12 @@ pub fn ceill(x: c_longdouble) callconv(.c) c_longdouble { |
| 140 | } | 167 | } |
| 141 | } | 168 | } |
| 142 | 169 | ||
| 170 | test "ceil16" { | ||
| 171 | try expect(__ceilh(1.3) == 2.0); | ||
| 172 | try expect(__ceilh(-1.3) == -1.0); | ||
| 173 | try expect(__ceilh(0.2) == 1.0); | ||
| 174 | } | ||
| 175 | |||
| 143 | test "ceil32" { | 176 | test "ceil32" { |
| 144 | try expect(ceilf(1.3) == 2.0); | 177 | try expect(ceilf(1.3) == 2.0); |
| 145 | try expect(ceilf(-1.3) == -1.0); | 178 | try expect(ceilf(-1.3) == -1.0); |
| ... | @@ -152,12 +185,26 @@ test "ceil64" { | ... | @@ -152,12 +185,26 @@ test "ceil64" { |
| 152 | try expect(ceil(0.2) == 1.0); | 185 | try expect(ceil(0.2) == 1.0); |
| 153 | } | 186 | } |
| 154 | 187 | ||
| 188 | test "ceil80" { | ||
| 189 | try expect(__ceilx(1.3) == 2.0); | ||
| 190 | try expect(__ceilx(-1.3) == -1.0); | ||
| 191 | try expect(__ceilx(0.2) == 1.0); | ||
| 192 | } | ||
| 193 | |||
| 155 | test "ceil128" { | 194 | test "ceil128" { |
| 156 | try expect(ceilq(1.3) == 2.0); | 195 | try expect(ceilq(1.3) == 2.0); |
| 157 | try expect(ceilq(-1.3) == -1.0); | 196 | try expect(ceilq(-1.3) == -1.0); |
| 158 | try expect(ceilq(0.2) == 1.0); | 197 | try expect(ceilq(0.2) == 1.0); |
| 159 | } | 198 | } |
| 160 | 199 | ||
| 200 | test "ceil16.special" { | ||
| 201 | try expect(__ceilh(0.0) == 0.0); | ||
| 202 | try expect(__ceilh(-0.0) == -0.0); | ||
| 203 | try expect(math.isPositiveInf(__ceilh(math.inf(f16)))); | ||
| 204 | try expect(math.isNegativeInf(__ceilh(-math.inf(f16)))); | ||
| 205 | try expect(math.isNan(__ceilh(math.nan(f16)))); | ||
| 206 | } | ||
| 207 | |||
| 161 | test "ceil32.special" { | 208 | test "ceil32.special" { |
| 162 | try expect(ceilf(0.0) == 0.0); | 209 | try expect(ceilf(0.0) == 0.0); |
| 163 | try expect(ceilf(-0.0) == -0.0); | 210 | try expect(ceilf(-0.0) == -0.0); |
| ... | @@ -174,6 +221,14 @@ test "ceil64.special" { | ... | @@ -174,6 +221,14 @@ test "ceil64.special" { |
| 174 | try expect(math.isNan(ceil(math.nan(f64)))); | 221 | try expect(math.isNan(ceil(math.nan(f64)))); |
| 175 | } | 222 | } |
| 176 | 223 | ||
| 224 | test "ceil80.special" { | ||
| 225 | try expect(__ceilx(0.0) == 0.0); | ||
| 226 | try expect(__ceilx(-0.0) == -0.0); | ||
| 227 | try expect(math.isPositiveInf(__ceilx(math.inf(f80)))); | ||
| 228 | try expect(math.isNegativeInf(__ceilx(-math.inf(f80)))); | ||
| 229 | try expect(math.isNan(__ceilx(math.nan(f80)))); | ||
| 230 | } | ||
| 231 | |||
| 177 | test "ceil128.special" { | 232 | test "ceil128.special" { |
| 178 | try expect(ceilq(0.0) == 0.0); | 233 | try expect(ceilq(0.0) == 0.0); |
| 179 | try expect(ceilq(-0.0) == -0.0); | 234 | try expect(ceilq(-0.0) == -0.0); |
lib/compiler_rt/floor.zig+52-41| ... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
| 3 | //! | 3 | //! |
| 4 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c | 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 | 5 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c |
| 6 | //! https://git.musl-libc.org/cgit/musl/tree/src/math/floorl.c | ||
| 6 | 7 | ||
| 7 | const std = @import("std"); | 8 | const std = @import("std"); |
| 8 | const builtin = @import("builtin"); | 9 | const builtin = @import("builtin"); |
| ... | @@ -31,32 +32,17 @@ pub fn __floorh(x: f16) callconv(.c) f16 { | ... | @@ -31,32 +32,17 @@ pub fn __floorh(x: f16) callconv(.c) f16 { |
| 31 | const e = @as(i16, @intCast((u >> 10) & 31)) - 15; | 32 | const e = @as(i16, @intCast((u >> 10) & 31)) - 15; |
| 32 | var m: u16 = undefined; | 33 | var m: u16 = undefined; |
| 33 | 34 | ||
| 34 | // TODO: Shouldn't need this explicit check. | 35 | if (e >= 10) return x; |
| 35 | if (x == 0.0) { | ||
| 36 | return x; | ||
| 37 | } | ||
| 38 | |||
| 39 | if (e >= 10) { | ||
| 40 | return x; | ||
| 41 | } | ||
| 42 | 36 | ||
| 43 | if (e >= 0) { | 37 | if (e >= 0) { |
| 44 | m = @as(u16, 1023) >> @intCast(e); | 38 | m = @as(u16, 0x03FF) >> @intCast(e); |
| 45 | if (u & m == 0) { | 39 | if (u & m == 0) return x; |
| 46 | return x; | ||
| 47 | } | ||
| 48 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | 40 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); |
| 49 | if (u >> 15 != 0) { | 41 | if (u >> 15 != 0) u += m; |
| 50 | u += m; | ||
| 51 | } | ||
| 52 | return @bitCast(u & ~m); | 42 | return @bitCast(u & ~m); |
| 53 | } else { | 43 | } else { |
| 54 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | 44 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); |
| 55 | if (u >> 15 == 0) { | 45 | return if (u >> 15 == 0) 0.0 else if (u << 1 != 0) -1.0 else x; |
| 56 | return 0.0; | ||
| 57 | } else { | ||
| 58 | return -1.0; | ||
| 59 | } | ||
| 60 | } | 46 | } |
| 61 | } | 47 | } |
| 62 | 48 | ||
| ... | @@ -65,32 +51,17 @@ pub fn floorf(x: f32) callconv(.c) f32 { | ... | @@ -65,32 +51,17 @@ pub fn floorf(x: f32) callconv(.c) f32 { |
| 65 | const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F; | 51 | const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F; |
| 66 | var m: u32 = undefined; | 52 | var m: u32 = undefined; |
| 67 | 53 | ||
| 68 | // TODO: Shouldn't need this explicit check. | 54 | if (e >= 23) return x; |
| 69 | if (x == 0.0) { | ||
| 70 | return x; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (e >= 23) { | ||
| 74 | return x; | ||
| 75 | } | ||
| 76 | 55 | ||
| 77 | if (e >= 0) { | 56 | if (e >= 0) { |
| 78 | m = @as(u32, 0x007FFFFF) >> @intCast(e); | 57 | m = @as(u32, 0x007FFFFF) >> @intCast(e); |
| 79 | if (u & m == 0) { | 58 | if (u & m == 0) return x; |
| 80 | return x; | ||
| 81 | } | ||
| 82 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | 59 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); |
| 83 | if (u >> 31 != 0) { | 60 | if (u >> 31 != 0) u += m; |
| 84 | u += m; | ||
| 85 | } | ||
| 86 | return @bitCast(u & ~m); | 61 | return @bitCast(u & ~m); |
| 87 | } else { | 62 | } else { |
| 88 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); | 63 | if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120); |
| 89 | if (u >> 31 == 0) { | 64 | return if (u >> 31 == 0) 0.0 else if (u << 1 != 0) -1.0 else x; |
| 90 | return 0.0; | ||
| 91 | } else { | ||
| 92 | return -1.0; | ||
| 93 | } | ||
| 94 | } | 65 | } |
| 95 | } | 66 | } |
| 96 | 67 | ||
| ... | @@ -126,8 +97,34 @@ pub fn floor(x: f64) callconv(.c) f64 { | ... | @@ -126,8 +97,34 @@ pub fn floor(x: f64) callconv(.c) f64 { |
| 126 | } | 97 | } |
| 127 | 98 | ||
| 128 | pub fn __floorx(x: f80) callconv(.c) f80 { | 99 | pub fn __floorx(x: f80) callconv(.c) f80 { |
| 129 | // TODO: more efficient implementation | 100 | const f80_toint = 1.0 / math.floatEps(f80); |
| 130 | return @floatCast(floorq(x)); | 101 | |
| 102 | const u: u80 = @bitCast(x); | ||
| 103 | const e = (u >> 64) & 0x7FFF; | ||
| 104 | var y: f80 = undefined; | ||
| 105 | |||
| 106 | if (e >= 0x3FFF + 64 or x == 0) { | ||
| 107 | return x; | ||
| 108 | } | ||
| 109 | |||
| 110 | if (u >> 79 != 0) { | ||
| 111 | y = x - f80_toint + f80_toint - x; | ||
| 112 | } else { | ||
| 113 | y = x + f80_toint - f80_toint - x; | ||
| 114 | } | ||
| 115 | |||
| 116 | if (e <= 0x3FFF - 1) { | ||
| 117 | if (common.want_float_exceptions) mem.doNotOptimizeAway(y); | ||
| 118 | if (u >> 79 != 0) { | ||
| 119 | return -1.0; | ||
| 120 | } else { | ||
| 121 | return 0.0; | ||
| 122 | } | ||
| 123 | } else if (y > 0) { | ||
| 124 | return x + y - 1; | ||
| 125 | } else { | ||
| 126 | return x + y; | ||
| 127 | } | ||
| 131 | } | 128 | } |
| 132 | 129 | ||
| 133 | pub fn floorq(x: f128) callconv(.c) f128 { | 130 | pub fn floorq(x: f128) callconv(.c) f128 { |
| ... | @@ -188,6 +185,12 @@ test "floor64" { | ... | @@ -188,6 +185,12 @@ test "floor64" { |
| 188 | try expect(floor(0.2) == 0.0); | 185 | try expect(floor(0.2) == 0.0); |
| 189 | } | 186 | } |
| 190 | 187 | ||
| 188 | test "floor80" { | ||
| 189 | try expect(__floorx(1.3) == 1.0); | ||
| 190 | try expect(__floorx(-1.3) == -2.0); | ||
| 191 | try expect(__floorx(0.2) == 0.0); | ||
| 192 | } | ||
| 193 | |||
| 191 | test "floor128" { | 194 | test "floor128" { |
| 192 | try expect(floorq(1.3) == 1.0); | 195 | try expect(floorq(1.3) == 1.0); |
| 193 | try expect(floorq(-1.3) == -2.0); | 196 | try expect(floorq(-1.3) == -2.0); |
| ... | @@ -218,6 +221,14 @@ test "floor64.special" { | ... | @@ -218,6 +221,14 @@ test "floor64.special" { |
| 218 | try expect(math.isNan(floor(math.nan(f64)))); | 221 | try expect(math.isNan(floor(math.nan(f64)))); |
| 219 | } | 222 | } |
| 220 | 223 | ||
| 224 | test "floor80.special" { | ||
| 225 | try expect(__floorx(0.0) == 0.0); | ||
| 226 | try expect(__floorx(-0.0) == -0.0); | ||
| 227 | try expect(math.isPositiveInf(__floorx(math.inf(f80)))); | ||
| 228 | try expect(math.isNegativeInf(__floorx(-math.inf(f80)))); | ||
| 229 | try expect(math.isNan(__floorx(math.nan(f80)))); | ||
| 230 | } | ||
| 231 | |||
| 221 | test "floor128.special" { | 232 | test "floor128.special" { |
| 222 | try expect(floorq(0.0) == 0.0); | 233 | try expect(floorq(0.0) == 0.0); |
| 223 | try expect(floorq(-0.0) == -0.0); | 234 | try expect(floorq(-0.0) == -0.0); |