authorgravatar for 3575188313@qq.comZhenming-Lin <3575188313@qq.com> 2025-09-25 04:40:40+08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-24 20:57:25-07:00
log99323a4da1617ba8fcf74656004dd5ad8d90dae1
tree6b2b641ebc5915dee34ff35dbfbb079a708b8d0a
parent91b0adc4c15a273b7a8a94371941a3f3f7fd2232

improve impl of `__floorh`, `__floorx`, `__ceilh` and `__ceilx`


2 files changed, 129 insertions(+), 63 deletions(-)

lib/compiler_rt/ceil.zig+77-22
......@@ -3,6 +3,7 @@
33//!
44//! https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
55//! 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
67
78const std = @import("std");
89const builtin = @import("builtin");
......@@ -27,8 +28,23 @@ comptime {
2728}
2829
2930pub fn __ceilh(x: f16) callconv(.c) f16 {
30 // TODO: more efficient implementation
31 return @floatCast(ceilf(x));
31 var u: u16 = @bitCast(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 }
3248}
3349
3450pub fn ceilf(x: f32) callconv(.c) f32 {
......@@ -36,31 +52,18 @@ pub fn ceilf(x: f32) callconv(.c) f32 {
3652 const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F;
3753 var m: u32 = undefined;
3854
39 // TODO: Shouldn't need this explicit check.
40 if (x == 0.0) {
41 return x;
42 }
55 if (e >= 23) return x;
4356
44 if (e >= 23) {
45 return x;
46 } else if (e >= 0) {
57 if (e >= 0) {
4758 m = @as(u32, 0x007FFFFF) >> @intCast(e);
48 if (u & m == 0) {
49 return x;
50 }
59 if (u & m == 0) return x;
5160 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
52 if (u >> 31 == 0) {
53 u += m;
54 }
61 if (u >> 31 == 0) u += m;
5562 u &= ~m;
5663 return @bitCast(u);
5764 } else {
5865 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
59 if (u >> 31 != 0) {
60 return -0.0;
61 } else {
62 return 1.0;
63 }
66 return if (u >> 31 != 0) -0.0 else if (u << 1 != 0) 1.0 else x;
6467 }
6568}
6669
......@@ -96,8 +99,32 @@ pub fn ceil(x: f64) callconv(.c) f64 {
9699}
97100
98101pub fn __ceilx(x: f80) callconv(.c) f80 {
99 // TODO: more efficient implementation
100 return @floatCast(ceilq(x));
102 const f80_toint = 1.0 / math.floatEps(f80);
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 }
101128}
102129
103130pub fn ceilq(x: f128) callconv(.c) f128 {
......@@ -140,6 +167,12 @@ pub fn ceill(x: c_longdouble) callconv(.c) c_longdouble {
140167 }
141168}
142169
170test "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
143176test "ceil32" {
144177 try expect(ceilf(1.3) == 2.0);
145178 try expect(ceilf(-1.3) == -1.0);
......@@ -152,12 +185,26 @@ test "ceil64" {
152185 try expect(ceil(0.2) == 1.0);
153186}
154187
188test "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
155194test "ceil128" {
156195 try expect(ceilq(1.3) == 2.0);
157196 try expect(ceilq(-1.3) == -1.0);
158197 try expect(ceilq(0.2) == 1.0);
159198}
160199
200test "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
161208test "ceil32.special" {
162209 try expect(ceilf(0.0) == 0.0);
163210 try expect(ceilf(-0.0) == -0.0);
......@@ -174,6 +221,14 @@ test "ceil64.special" {
174221 try expect(math.isNan(ceil(math.nan(f64))));
175222}
176223
224test "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
177232test "ceil128.special" {
178233 try expect(ceilq(0.0) == 0.0);
179234 try expect(ceilq(-0.0) == -0.0);
lib/compiler_rt/floor.zig+52-41
......@@ -3,6 +3,7 @@
33//!
44//! https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c
55//! 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
67
78const std = @import("std");
89const builtin = @import("builtin");
......@@ -31,32 +32,17 @@ pub fn __floorh(x: f16) callconv(.c) f16 {
3132 const e = @as(i16, @intCast((u >> 10) & 31)) - 15;
3233 var m: u16 = undefined;
3334
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 }
35 if (e >= 10) return x;
4236
4337 if (e >= 0) {
44 m = @as(u16, 1023) >> @intCast(e);
45 if (u & m == 0) {
46 return x;
47 }
38 m = @as(u16, 0x03FF) >> @intCast(e);
39 if (u & m == 0) return x;
4840 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
49 if (u >> 15 != 0) {
50 u += m;
51 }
41 if (u >> 15 != 0) u += m;
5242 return @bitCast(u & ~m);
5343 } else {
5444 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 }
45 return if (u >> 15 == 0) 0.0 else if (u << 1 != 0) -1.0 else x;
6046 }
6147}
6248
......@@ -65,32 +51,17 @@ pub fn floorf(x: f32) callconv(.c) f32 {
6551 const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F;
6652 var m: u32 = undefined;
6753
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 }
54 if (e >= 23) return x;
7655
7756 if (e >= 0) {
7857 m = @as(u32, 0x007FFFFF) >> @intCast(e);
79 if (u & m == 0) {
80 return x;
81 }
58 if (u & m == 0) return x;
8259 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
83 if (u >> 31 != 0) {
84 u += m;
85 }
60 if (u >> 31 != 0) u += m;
8661 return @bitCast(u & ~m);
8762 } else {
8863 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 }
64 return if (u >> 31 == 0) 0.0 else if (u << 1 != 0) -1.0 else x;
9465 }
9566}
9667
......@@ -126,8 +97,34 @@ pub fn floor(x: f64) callconv(.c) f64 {
12697}
12798
12899pub fn __floorx(x: f80) callconv(.c) f80 {
129 // TODO: more efficient implementation
130 return @floatCast(floorq(x));
100 const f80_toint = 1.0 / math.floatEps(f80);
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 }
131128}
132129
133130pub fn floorq(x: f128) callconv(.c) f128 {
......@@ -188,6 +185,12 @@ test "floor64" {
188185 try expect(floor(0.2) == 0.0);
189186}
190187
188test "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
191194test "floor128" {
192195 try expect(floorq(1.3) == 1.0);
193196 try expect(floorq(-1.3) == -2.0);
......@@ -218,6 +221,14 @@ test "floor64.special" {
218221 try expect(math.isNan(floor(math.nan(f64))));
219222}
220223
224test "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
221232test "floor128.special" {
222233 try expect(floorq(0.0) == 0.0);
223234 try expect(floorq(-0.0) == -0.0);