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 @@...@@ -3,6 +3,7 @@
3//!3//!
4//! https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c4//! https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
5//! https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c5//! 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
7const std = @import("std");8const std = @import("std");
8const builtin = @import("builtin");9const builtin = @import("builtin");
...@@ -27,8 +28,23 @@ comptime {...@@ -27,8 +28,23 @@ comptime {
27}28}
2829
29pub fn __ceilh(x: f16) callconv(.c) f16 {30pub fn __ceilh(x: f16) callconv(.c) f16 {
30 // TODO: more efficient implementation31 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}
3349
34pub fn ceilf(x: f32) callconv(.c) f32 {50pub 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;
3854
39 // TODO: Shouldn't need this explicit check.55 if (e >= 23) return x;
40 if (x == 0.0) {
41 return x;
42 }
4356
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}
6669
...@@ -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}
97100
98pub fn __ceilx(x: f80) callconv(.c) f80 {101pub fn __ceilx(x: f80) callconv(.c) f80 {
99 // TODO: more efficient implementation102 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}
102129
103pub fn ceilq(x: f128) callconv(.c) f128 {130pub 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}
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
143test "ceil32" {176test "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}
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
155test "ceil128" {194test "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}
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
161test "ceil32.special" {208test "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}
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
177test "ceil128.special" {232test "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.c4//! https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c
5//! https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c5//! 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
7const std = @import("std");8const std = @import("std");
8const builtin = @import("builtin");9const 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;
3334
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 }
4236
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}
6248
...@@ -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;
6753
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 }
7655
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}
9667
...@@ -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}
12798
128pub fn __floorx(x: f80) callconv(.c) f80 {99pub fn __floorx(x: f80) callconv(.c) f80 {
129 // TODO: more efficient implementation100 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}
132129
133pub fn floorq(x: f128) callconv(.c) f128 {130pub 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}
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
191test "floor128" {194test "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}
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
221test "floor128.special" {232test "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);