master
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//! https://git.musl-libc.org/cgit/musl/tree/src/math/floorl.c
7
8const std = @import("std");
9const builtin = @import("builtin");
10const math = std.math;
11const mem = std.mem;
12const expect = std.testing.expect;
13const arch = builtin.cpu.arch;
14const common = @import("common.zig");
15
16pub const panic = common.panic;
17
18comptime {
19 @export(&__floorh, .{ .name = "__floorh", .linkage = common.linkage, .visibility = common.visibility });
20 @export(&floorf, .{ .name = "floorf", .linkage = common.linkage, .visibility = common.visibility });
21 @export(&floor, .{ .name = "floor", .linkage = common.linkage, .visibility = common.visibility });
22 @export(&__floorx, .{ .name = "__floorx", .linkage = common.linkage, .visibility = common.visibility });
23 if (common.want_ppc_abi) {
24 @export(&floorq, .{ .name = "floorf128", .linkage = common.linkage, .visibility = common.visibility });
25 }
26 @export(&floorq, .{ .name = "floorq", .linkage = common.linkage, .visibility = common.visibility });
27 @export(&floorl, .{ .name = "floorl", .linkage = common.linkage, .visibility = common.visibility });
28}
29
30pub fn __floorh(x: f16) callconv(.c) f16 {
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 return @bitCast(u & ~m);
43 } else {
44 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
45 return if (u >> 15 == 0) 0.0 else if (u << 1 != 0) -1.0 else x;
46 }
47}
48
49pub fn floorf(x: f32) callconv(.c) f32 {
50 var u: u32 = @bitCast(x);
51 const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F;
52 var m: u32 = undefined;
53
54 if (e >= 23) return x;
55
56 if (e >= 0) {
57 m = @as(u32, 0x007FFFFF) >> @intCast(e);
58 if (u & m == 0) return x;
59 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
60 if (u >> 31 != 0) u += m;
61 return @bitCast(u & ~m);
62 } else {
63 if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
64 return if (u >> 31 == 0) 0.0 else if (u << 1 != 0) -1.0 else x;
65 }
66}
67
68pub fn floor(x: f64) callconv(.c) f64 {
69 const f64_toint = 1.0 / math.floatEps(f64);
70
71 const u: u64 = @bitCast(x);
72 const e = (u >> 52) & 0x7FF;
73 var y: f64 = undefined;
74
75 if (e >= 0x3FF + 52 or x == 0) {
76 return x;
77 }
78
79 if (u >> 63 != 0) {
80 y = x - f64_toint + f64_toint - x;
81 } else {
82 y = x + f64_toint - f64_toint - x;
83 }
84
85 if (e <= 0x3FF - 1) {
86 if (common.want_float_exceptions) mem.doNotOptimizeAway(y);
87 if (u >> 63 != 0) {
88 return -1.0;
89 } else {
90 return 0.0;
91 }
92 } else if (y > 0) {
93 return x + y - 1;
94 } else {
95 return x + y;
96 }
97}
98
99pub fn __floorx(x: f80) callconv(.c) f80 {
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 }
128}
129
130pub fn floorq(x: f128) callconv(.c) f128 {
131 const f128_toint = 1.0 / math.floatEps(f128);
132
133 const u: u128 = @bitCast(x);
134 const e = (u >> 112) & 0x7FFF;
135 var y: f128 = undefined;
136
137 if (e >= 0x3FFF + 112 or x == 0) return x;
138
139 if (u >> 127 != 0) {
140 y = x - f128_toint + f128_toint - x;
141 } else {
142 y = x + f128_toint - f128_toint - x;
143 }
144
145 if (e <= 0x3FFF - 1) {
146 if (common.want_float_exceptions) mem.doNotOptimizeAway(y);
147 if (u >> 127 != 0) {
148 return -1.0;
149 } else {
150 return 0.0;
151 }
152 } else if (y > 0) {
153 return x + y - 1;
154 } else {
155 return x + y;
156 }
157}
158
159pub fn floorl(x: c_longdouble) callconv(.c) c_longdouble {
160 switch (@typeInfo(c_longdouble).float.bits) {
161 16 => return __floorh(x),
162 32 => return floorf(x),
163 64 => return floor(x),
164 80 => return __floorx(x),
165 128 => return floorq(x),
166 else => @compileError("unreachable"),
167 }
168}
169
170test "floor16" {
171 try expect(__floorh(1.3) == 1.0);
172 try expect(__floorh(-1.3) == -2.0);
173 try expect(__floorh(0.2) == 0.0);
174}
175
176test "floor32" {
177 try expect(floorf(1.3) == 1.0);
178 try expect(floorf(-1.3) == -2.0);
179 try expect(floorf(0.2) == 0.0);
180}
181
182test "floor64" {
183 try expect(floor(1.3) == 1.0);
184 try expect(floor(-1.3) == -2.0);
185 try expect(floor(0.2) == 0.0);
186}
187
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
194test "floor128" {
195 try expect(floorq(1.3) == 1.0);
196 try expect(floorq(-1.3) == -2.0);
197 try expect(floorq(0.2) == 0.0);
198}
199
200test "floor16.special" {
201 try expect(__floorh(0.0) == 0.0);
202 try expect(__floorh(-0.0) == -0.0);
203 try expect(math.isPositiveInf(__floorh(math.inf(f16))));
204 try expect(math.isNegativeInf(__floorh(-math.inf(f16))));
205 try expect(math.isNan(__floorh(math.nan(f16))));
206}
207
208test "floor32.special" {
209 try expect(floorf(0.0) == 0.0);
210 try expect(floorf(-0.0) == -0.0);
211 try expect(math.isPositiveInf(floorf(math.inf(f32))));
212 try expect(math.isNegativeInf(floorf(-math.inf(f32))));
213 try expect(math.isNan(floorf(math.nan(f32))));
214}
215
216test "floor64.special" {
217 try expect(floor(0.0) == 0.0);
218 try expect(floor(-0.0) == -0.0);
219 try expect(math.isPositiveInf(floor(math.inf(f64))));
220 try expect(math.isNegativeInf(floor(-math.inf(f64))));
221 try expect(math.isNan(floor(math.nan(f64))));
222}
223
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
232test "floor128.special" {
233 try expect(floorq(0.0) == 0.0);
234 try expect(floorq(-0.0) == -0.0);
235 try expect(math.isPositiveInf(floorq(math.inf(f128))));
236 try expect(math.isNegativeInf(floorq(-math.inf(f128))));
237 try expect(math.isNan(floorq(math.nan(f128))));
238}