1const builtin = @import("builtin");
2
3const std = @import("std");
4const math = std.math;
5const ld = math.long_double;
6
7const symbol = @import("../c.zig").symbol;
8
9comptime {
10 if (builtin.target.isMinGW()) {
11 symbol(&isnan, "isnan");
12 symbol(&isnan, "__isnan");
13 symbol(&isnanf, "isnanf");
14 symbol(&isnanf, "__isnanf");
15 symbol(&isnanl, "isnanl");
16 symbol(&isnanl, "__isnanl");
17
18 symbol(&math.floatTrueMin(f64), "__DENORM");
19 symbol(&math.inf(f64), "__INF");
20 symbol(&math.nan(f64), "__QNAN");
21 symbol(&math.snan(f64), "__SNAN");
22
23 symbol(&math.floatTrueMin(f32), "__DENORMF");
24 symbol(&math.inf(f32), "__INFF");
25 symbol(&math.nan(f32), "__QNANF");
26 symbol(&math.snan(f32), "__SNANF");
27
28 symbol(&math.floatTrueMin(c_longdouble), "__DENORML");
29 symbol(&math.inf(c_longdouble), "__INFL");
30 symbol(&math.nan(c_longdouble), "__QNANL");
31 symbol(&math.snan(c_longdouble), "__SNANL");
32 }
33
34 if (builtin.target.isMinGW() or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
35 symbol(&frexpf, "frexpf");
36 symbol(&frexpl, "frexpl");
37 symbol(&hypotf, "hypotf");
38 symbol(&hypotl, "hypotl");
39 symbol(&lrintl, "lrintl");
40 symbol(&lroundl, "lroundl");
41 symbol(&modfl, "modfl");
42 symbol(&rintl, "rintl");
43 }
44
45 if ((builtin.target.isMinGW() and @sizeOf(f64) != @sizeOf(c_longdouble)) or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
46 symbol(&atanl, "atanl");
47 symbol(&copysignl, "copysignl");
48 symbol(&fdiml, "fdiml");
49 symbol(&nanl, "nanl");
50 }
51
52 if ((builtin.target.isMinGW() and builtin.cpu.arch == .x86) or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
53 symbol(&acosf, "acosf");
54 symbol(&atanf, "atanf");
55 symbol(&coshf, "coshf");
56 symbol(&modff, "modff");
57 symbol(&tanhf, "tanhf");
58 }
59
60 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
61 symbol(&acos, "acos");
62 symbol(&acoshf, "acoshf");
63 symbol(&asin, "asin");
64 symbol(&atan, "atan");
65 symbol(&cbrt, "cbrt");
66 symbol(&cbrtf, "cbrtf");
67 symbol(&cosh, "cosh");
68 symbol(&exp10, "exp10");
69 symbol(&exp10f, "exp10f");
70 symbol(&fdim, "fdim");
71 symbol(&fdimf, "fdimf");
72 symbol(&finite, "finite");
73 symbol(&finitef, "finitef");
74 symbol(&frexp, "frexp");
75 symbol(&hypot, "hypot");
76 symbol(&log1p, "log1p");
77 symbol(&log1pf, "log1pf");
78 symbol(&lrint, "lrint");
79 symbol(&lrintf, "lrintf");
80 symbol(&lround, "lround");
81 symbol(&lroundf, "lroundf");
82 symbol(&modf, "modf");
83 symbol(&nan, "nan");
84 symbol(&nanf, "nanf");
85 symbol(&pow10, "pow10");
86 symbol(&pow10f, "pow10f");
87 symbol(&tanh, "tanh");
88 }
89
90 if (builtin.target.isMuslLibC()) {
91 symbol(&copysign, "copysign");
92 symbol(&copysignf, "copysignf");
93 symbol(&rint, "rint");
94 symbol(&rintf, "rintf");
95 }
96}
97
98fn acos(x: f64) callconv(.c) f64 {
99 return math.acos(x);
100}
101
102fn acosf(x: f32) callconv(.c) f32 {
103 return math.acos(x);
104}
105
106fn acoshf(x: f32) callconv(.c) f32 {
107 return math.acosh(x);
108}
109
110fn asin(x: f64) callconv(.c) f64 {
111 return math.asin(x);
112}
113
114fn atan(x: f64) callconv(.c) f64 {
115 return math.atan(x);
116}
117
118fn atanf(x: f32) callconv(.c) f32 {
119 return math.atan(x);
120}
121
122fn atanl(x: c_longdouble) callconv(.c) c_longdouble {
123 return switch (@typeInfo(c_longdouble).float.bits) {
124 64 => std.c.atan(x),
125 else => math.atan(x),
126 };
127}
128
129fn cbrt(x: f64) callconv(.c) f64 {
130 return math.cbrt(x);
131}
132
133fn cbrtf(x: f32) callconv(.c) f32 {
134 return math.cbrt(x);
135}
136
137fn copysign(x: f64, y: f64) callconv(.c) f64 {
138 return math.copysign(x, y);
139}
140
141fn copysignf(x: f32, y: f32) callconv(.c) f32 {
142 return math.copysign(x, y);
143}
144
145fn copysignl(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble {
146 return switch (@typeInfo(c_longdouble).float.bits) {
147 64 => std.c.copysign(x, y),
148 else => math.copysign(x, y),
149 };
150}
151
152fn cosh(x: f64) callconv(.c) f64 {
153 return math.cosh(x);
154}
155
156fn coshf(x: f32) callconv(.c) f32 {
157 return math.cosh(x);
158}
159
160fn exp10(x: f64) callconv(.c) f64 {
161 return math.pow(f64, 10.0, x);
162}
163
164fn exp10f(x: f32) callconv(.c) f32 {
165 return math.pow(f32, 10.0, x);
166}
167
168fn fdimGeneric(comptime T: type, x: T, y: T) T {
169 if (math.isNan(x))
170 return x;
171
172 if (math.isNan(y))
173 return y;
174
175 if (x > y)
176 return x - y;
177 return 0;
178}
179
180fn fdim(x: f64, y: f64) callconv(.c) f64 {
181 return fdimGeneric(f64, x, y);
182}
183
184fn fdimf(x: f32, y: f32) callconv(.c) f32 {
185 return fdimGeneric(f32, x, y);
186}
187
188fn fdiml(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble {
189 return switch (@typeInfo(c_longdouble).float.bits) {
190 64 => std.c.fdim(x, y),
191 else => fdimGeneric(c_longdouble, x, y),
192 };
193}
194
195fn finite(x: f64) callconv(.c) c_int {
196 return @intFromBool(math.isFinite(x));
197}
198
199fn finitef(x: f32) callconv(.c) c_int {
200 return @intFromBool(math.isFinite(x));
201}
202
203fn frexpGeneric(comptime T: type, x: T, e: *c_int) T {
204 // libc expects `*e` to be unspecified in this case; an unspecified C value
205 // should be a valid value of the relevant type, yet Zig's std
206 // implementation sets it to `undefined` -- which can even be nonsense
207 // according to the type (int). Therefore, we're setting it to a valid
208 // int value in Zig -- a zero.
209 //
210 // This mirrors the handling of infinities, where libc also expects
211 // unspecified for the value of `*e` and Zig std sets it to a zero.
212 if (math.isNan(x)) {
213 e.* = 0;
214 return x;
215 }
216
217 const r = math.frexp(x);
218 e.* = r.exponent;
219 return r.significand;
220}
221
222fn frexp(x: f64, e: *c_int) callconv(.c) f64 {
223 return frexpGeneric(f64, x, e);
224}
225
226fn frexpf(x: f32, e: *c_int) callconv(.c) f32 {
227 return frexpGeneric(f32, x, e);
228}
229
230fn frexpl(x: c_longdouble, e: *c_int) callconv(.c) c_longdouble {
231 return switch (@typeInfo(c_longdouble).float.bits) {
232 64 => std.c.frexp(x, e),
233 else => frexpGeneric(c_longdouble, x, e),
234 };
235}
236
237fn hypot(x: f64, y: f64) callconv(.c) f64 {
238 return math.hypot(x, y);
239}
240
241fn hypotf(x: f32, y: f32) callconv(.c) f32 {
242 return math.hypot(x, y);
243}
244
245fn hypotl(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble {
246 return switch (@typeInfo(c_longdouble).float.bits) {
247 64 => std.c.hypot(x, y),
248 else => math.hypot(x, y),
249 };
250}
251
252fn isnan(x: f64) callconv(.c) c_int {
253 return @intFromBool(math.isNan(x));
254}
255
256fn isnanf(x: f32) callconv(.c) c_int {
257 return @intFromBool(math.isNan(x));
258}
259
260fn isnanl(x: c_longdouble) callconv(.c) c_int {
261 return @intFromBool(math.isNan(x));
262}
263
264fn log1p(x: f64) callconv(.c) f64 {
265 return math.log1p(x);
266}
267
268fn log1pf(x: f32) callconv(.c) f32 {
269 return math.log1p(x);
270}
271
272fn lrint(x: f64) callconv(.c) c_long {
273 return @trunc(rint(x));
274}
275
276fn lrintf(x: f32) callconv(.c) c_long {
277 return @trunc(rintf(x));
278}
279
280fn lrintl(x: c_longdouble) callconv(.c) c_long {
281 return @trunc(rintl(x));
282}
283
284fn lround(x: f64) callconv(.c) c_long {
285 return @round(x);
286}
287
288fn lroundf(x: f32) callconv(.c) c_long {
289 return @round(x);
290}
291
292fn lroundl(x: c_longdouble) callconv(.c) c_long {
293 return @round(x);
294}
295
296fn modfGeneric(comptime T: type, x: T, iptr: *T) T {
297 if (math.isNegativeInf(x)) {
298 iptr.* = -math.inf(T);
299 return -0.0;
300 }
301
302 if (math.isPositiveInf(x)) {
303 iptr.* = math.inf(T);
304 return 0.0;
305 }
306
307 if (math.isNan(x)) {
308 iptr.* = math.nan(T);
309 return math.nan(T);
310 }
311
312 const r = math.modf(x);
313 iptr.* = r.ipart;
314
315 // If the result is a negative zero, we must be explicit about
316 // returning a negative zero.
317 return if (math.isNegativeZero(x) or (x < 0.0 and x == r.ipart)) -0.0 else r.fpart;
318}
319
320fn modf(x: f64, iptr: *f64) callconv(.c) f64 {
321 return modfGeneric(f64, x, iptr);
322}
323
324fn modff(x: f32, iptr: *f32) callconv(.c) f32 {
325 return modfGeneric(f32, x, iptr);
326}
327
328fn modfl(x: c_longdouble, iptr: *c_longdouble) callconv(.c) c_longdouble {
329 return switch (@typeInfo(c_longdouble).float.bits) {
330 64 => std.c.modf(x, iptr),
331 else => modfGeneric(c_longdouble, x, iptr),
332 };
333}
334
335fn nan(_: [*:0]const c_char) callconv(.c) f64 {
336 return math.nan(f64);
337}
338
339fn nanf(_: [*:0]const c_char) callconv(.c) f32 {
340 return math.nan(f32);
341}
342
343fn nanl(_: [*:0]const c_char) callconv(.c) c_longdouble {
344 return math.nan(c_longdouble);
345}
346
347fn pow10(x: f64) callconv(.c) f64 {
348 return exp10(x);
349}
350
351fn pow10f(x: f32) callconv(.c) f32 {
352 return exp10f(x);
353}
354
355fn rint(x: f64) callconv(.c) f64 {
356 const toint: f64 = 1.0 / math.floatEps(f64);
357 const a: u64 = @bitCast(x);
358 const e = a >> 52 & 0x7ff;
359 const s = a >> 63;
360 var y: f64 = undefined;
361
362 if (e >= 0x3ff + 52) {
363 return x;
364 }
365 if (s == 1) {
366 y = x - toint + toint;
367 } else {
368 y = x + toint - toint;
369 }
370 if (y == 0) {
371 return if (s == 1) -0.0 else 0;
372 }
373 return y;
374}
375
376fn rintf(x: f32) callconv(.c) f32 {
377 const toint: f32 = 1.0 / math.floatEps(f32);
378 const a: u32 = @bitCast(x);
379 const e = a >> 23 & 0xff;
380 const s = a >> 31;
381 var y: f32 = undefined;
382
383 if (e >= 0x7f + 23) {
384 return x;
385 }
386
387 if (s == 1) {
388 y = x - toint + toint;
389 } else {
390 y = x + toint - toint;
391 }
392
393 if (y == 0) {
394 return if (s == 1) -0.0 else 0;
395 }
396 return y;
397}
398
399fn rintl(x: c_longdouble) callconv(.c) c_longdouble {
400 if (@typeInfo(c_longdouble).float.bits == 64)
401 return rint(x);
402
403 const toint: c_longdouble = 1 << math.floatFractionalBits(c_longdouble);
404 const se = ld.signExponent(x);
405
406 if (se & 0x7fff >= 0x3fff + math.floatFractionalBits(c_longdouble))
407 return x;
408
409 var y: c_longdouble = undefined;
410 if ((se >> 15) == 1) {
411 y = x - toint + toint;
412 } else {
413 y = x + toint - toint;
414 }
415
416 if (y == 0)
417 return 0 * x;
418 return y;
419}
420
421fn tanh(x: f64) callconv(.c) f64 {
422 return math.tanh(x);
423}
424
425fn tanhf(x: f32) callconv(.c) f32 {
426 return math.tanh(x);
427}