authorgravatar for me@gasinfinity.devGasInfinity <me@gasinfinity.dev> 2026-01-08 13:38:40+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-09 00:26:20+01:00
log7f6eab270493592d4c3e5788dfcb34fdbca80539
tree28996f8dd8b115e20e38ae5d95de5d511ba53e02
parentecea8cc16d783518d38c1022278336b422215232

feat(libzigc): add `nan`, `nanf`, `nanl` and `bsearch`

* also remove musl implementation

13 files changed, 78 insertions(+), 166 deletions(-)

lib/c/math.zig+33
...@@ -10,6 +10,27 @@ comptime {...@@ -10,6 +10,27 @@ comptime {
10 @export(&isnanf, .{ .name = "__isnanf", .linkage = common.linkage, .visibility = common.visibility });10 @export(&isnanf, .{ .name = "__isnanf", .linkage = common.linkage, .visibility = common.visibility });
11 @export(&isnanl, .{ .name = "isnanl", .linkage = common.linkage, .visibility = common.visibility });11 @export(&isnanl, .{ .name = "isnanl", .linkage = common.linkage, .visibility = common.visibility });
12 @export(&isnanl, .{ .name = "__isnanl", .linkage = common.linkage, .visibility = common.visibility });12 @export(&isnanl, .{ .name = "__isnanl", .linkage = common.linkage, .visibility = common.visibility });
13
14 @export(&std.math.nan(f64), .{ .name = "__QNAN", .linkage = common.linkage, .visibility = common.visibility });
15 @export(&std.math.snan(f64), .{ .name = "__SNAN", .linkage = common.linkage, .visibility = common.visibility });
16 @export(&std.math.inf(f64), .{ .name = "__INF", .linkage = common.linkage, .visibility = common.visibility });
17 @export(&std.math.floatTrueMin(f64), .{ .name = "__DENORM", .linkage = common.linkage, .visibility = common.visibility });
18
19 @export(&std.math.nan(f32), .{ .name = "__QNANF", .linkage = common.linkage, .visibility = common.visibility });
20 @export(&std.math.snan(f32), .{ .name = "__SNANF", .linkage = common.linkage, .visibility = common.visibility });
21 @export(&std.math.inf(f32), .{ .name = "__INFF", .linkage = common.linkage, .visibility = common.visibility });
22 @export(&std.math.floatTrueMin(f32), .{ .name = "__DENORMF", .linkage = common.linkage, .visibility = common.visibility });
23
24 @export(&std.math.nan(c_longdouble), .{ .name = "__QNANL", .linkage = common.linkage, .visibility = common.visibility });
25 @export(&std.math.snan(c_longdouble), .{ .name = "__SNANL", .linkage = common.linkage, .visibility = common.visibility });
26 @export(&std.math.inf(c_longdouble), .{ .name = "__INFL", .linkage = common.linkage, .visibility = common.visibility });
27 @export(&std.math.floatTrueMin(c_longdouble), .{ .name = "__DENORML", .linkage = common.linkage, .visibility = common.visibility });
28 }
29
30 if (builtin.target.isMinGW() or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
31 @export(&nan, .{ .name = "nan", .linkage = common.linkage, .visibility = common.visibility });
32 @export(&nanf, .{ .name = "nanf", .linkage = common.linkage, .visibility = common.visibility });
33 @export(&nanl, .{ .name = "nanl", .linkage = common.linkage, .visibility = common.visibility });
13 }34 }
14}35}
1536
...@@ -24,3 +45,15 @@ fn isnanf(x: f32) callconv(.c) c_int {...@@ -24,3 +45,15 @@ fn isnanf(x: f32) callconv(.c) c_int {
24fn isnanl(x: c_longdouble) callconv(.c) c_int {45fn isnanl(x: c_longdouble) callconv(.c) c_int {
25 return if (std.math.isNan(x)) 1 else 0;46 return if (std.math.isNan(x)) 1 else 0;
26}47}
48
49fn nan(_: [*:0]const c_char) callconv(.c) f64 {
50 return std.math.nan(f64);
51}
52
53fn nanf(_: [*:0]const c_char) callconv(.c) f32 {
54 return std.math.nan(f32);
55}
56
57fn nanl(_: [*:0]const c_char) callconv(.c) c_longdouble {
58 return std.math.nan(c_longdouble);
59}
lib/c/stdlib.zig+45
...@@ -18,6 +18,8 @@ comptime {...@@ -18,6 +18,8 @@ comptime {
1818
19 @export(&qsort_r, .{ .name = "qsort_r", .linkage = common.linkage, .visibility = common.visibility });19 @export(&qsort_r, .{ .name = "qsort_r", .linkage = common.linkage, .visibility = common.visibility });
20 @export(&qsort, .{ .name = "qsort", .linkage = common.linkage, .visibility = common.visibility });20 @export(&qsort, .{ .name = "qsort", .linkage = common.linkage, .visibility = common.visibility });
21
22 @export(&bsearch, .{ .name = "bsearch", .linkage = common.linkage, .visibility = common.visibility });
21 }23 }
22}24}
2325
...@@ -95,6 +97,26 @@ fn qsort(base: *anyopaque, n: usize, size: usize, compare: *const fn (a: *const...@@ -95,6 +97,26 @@ fn qsort(base: *anyopaque, n: usize, size: usize, compare: *const fn (a: *const
95 }).wrap, @constCast(compare));97 }).wrap, @constCast(compare));
96}98}
9799
100// NOTE: Despite its name, `bsearch` doesn't need to be implemented using binary search or make any complexity guarantee.
101fn bsearch(key: *const anyopaque, base: *const anyopaque, n: usize, size: usize, compare: *const fn (a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int) callconv(.c) ?*anyopaque {
102 const base_bytes: [*]const u8 = @ptrCast(base);
103 var low: usize = 0;
104 var high: usize = n;
105
106 while (low < high) {
107 // Avoid overflowing in the midpoint calculation
108 const mid = low + (high - low) / 2;
109 const elem = &base_bytes[mid * size];
110
111 switch (std.math.order(compare(key, elem), 0)) {
112 .eq => return @constCast(elem),
113 .gt => low = mid + 1,
114 .lt => high = mid,
115 }
116 }
117 return null;
118}
119
98test abs {120test abs {
99 const val: c_int = -10;121 const val: c_int = -10;
100 try std.testing.expectEqual(10, abs(val));122 try std.testing.expectEqual(10, abs(val));
...@@ -124,3 +146,26 @@ test lldiv {...@@ -124,3 +146,26 @@ test lldiv {
124 const expected: lldiv_t = .{ .quot = 1, .rem = 2 };146 const expected: lldiv_t = .{ .quot = 1, .rem = 2 };
125 try std.testing.expectEqual(expected, lldiv(5, 3));147 try std.testing.expectEqual(expected, lldiv(5, 3));
126}148}
149
150test bsearch {
151 const Comparison = struct {
152 pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int {
153 const a_u16: *const u16 = @ptrCast(@alignCast(a));
154 const b_u16: *const u16 = @ptrCast(@alignCast(b));
155
156 return switch (std.math.order(a_u16.*, b_u16.*)) {
157 .gt => 1,
158 .eq => 0,
159 .lt => -1,
160 };
161 }
162 };
163
164 const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 };
165
166 try std.testing.expectEqual(@as(?*anyopaque, null), bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare));
167
168 for (items) |*value| {
169 try std.testing.expectEqual(@as(*const anyopaque, value), bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare));
170 }
171}
lib/libc/mingw/math/fp_consts.c deleted-20
...@@ -1,20 +0,0 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#include "fp_consts.h"
7const union _ieee_rep __QNAN = { __DOUBLE_QNAN_REP };
8const union _ieee_rep __SNAN = { __DOUBLE_SNAN_REP };
9const union _ieee_rep __INF = { __DOUBLE_INF_REP };
10const union _ieee_rep __DENORM = { __DOUBLE_DENORM_REP };
11
12/* ISO C99 */
13#undef nan
14/* FIXME */
15double nan (const char *);
16double nan (const char * tagp __attribute__((unused)) )
17{
18 return __QNAN.double_val;
19}
20
lib/libc/mingw/math/fp_consts.h deleted-50
...@@ -1,50 +0,0 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#ifndef _FP_CONSTS_H
7#define _FP_CONSTS_H
8
9/*
10According to IEEE 754 a QNaN has exponent bits of all 1 values and
11initial significand bit of 1. A SNaN has has an exponent of all 1
12values and initial significand bit of 0 (with one or more other
13significand bits of 1). An Inf has significand of 0 and
14exponent of all 1 values. A denormal value has all exponent bits of 0.
15*/
16
17
18#define __DOUBLE_INF_REP { 0, 0, 0, 0x7ff0 }
19#define __DOUBLE_QNAN_REP { 0, 0, 0, 0x7ff8 }
20#define __DOUBLE_SNAN_REP { 0, 0, 0, 0x7ff0 }
21#define __DOUBLE_DENORM_REP {1, 0, 0, 0}
22
23#define D_NAN_MASK 0x7ff0000000000000LL /* this will mask NaN's and Inf's */
24
25#define __FLOAT_INF_REP { 0, 0x7f80 }
26#define __FLOAT_QNAN_REP { 0, 0x7fc0 }
27#define __FLOAT_SNAN_REP { 0, 0x7f80 }
28#define __FLOAT_DENORM_REP {1,0}
29
30#define F_NAN_MASK 0x7f800000
31
32/*
33 This assumes no implicit (hidden) bit in extended mode.
34 Padded to 96 bits
35 */
36#define __LONG_DOUBLE_INF_REP { 0, 0, 0, 0x8000, 0x7fff, 0 }
37#define __LONG_DOUBLE_QNAN_REP { 0, 0, 0, 0xc000, 0x7fff, 0 }
38#define __LONG_DOUBLE_SNAN_REP { 0, 0, 0, 0x8000, 0x7fff, 0 }
39#define __LONG_DOUBLE_DENORM_REP {1, 0, 0, 0, 0, 0}
40
41union _ieee_rep
42{
43 unsigned short rep[6];
44 float float_val;
45 double double_val;
46 long double ldouble_val;
47};
48
49#endif /* _FP_CONSTS_H */
50
lib/libc/mingw/math/fp_constsf.c deleted-22
...@@ -1,22 +0,0 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#include "fp_consts.h"
7
8const union _ieee_rep __QNANF = { __FLOAT_QNAN_REP };
9const union _ieee_rep __SNANF = { __FLOAT_SNAN_REP };
10const union _ieee_rep __INFF = { __FLOAT_INF_REP };
11const union _ieee_rep __DENORMF = { __FLOAT_DENORM_REP };
12
13/* ISO C99 */
14#undef nanf
15/* FIXME */
16float nanf(const char *);
17
18float nanf(const char * tagp __attribute__((unused)) )
19{
20 return __QNANF.float_val;
21}
22
lib/libc/mingw/math/fp_constsl.c deleted-25
...@@ -1,25 +0,0 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#include "fp_consts.h"
7#include <math.h>
8
9const union _ieee_rep __QNANL = { __LONG_DOUBLE_QNAN_REP };
10const union _ieee_rep __SNANL = { __LONG_DOUBLE_SNAN_REP };
11const union _ieee_rep __INFL = { __LONG_DOUBLE_INF_REP };
12const union _ieee_rep __DENORML = { __LONG_DOUBLE_DENORM_REP };
13
14#undef nanl
15/* FIXME */
16long double nanl (const char *);
17long double nanl (const char * tagp __attribute__((unused)) )
18{
19#if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
20 return nan("");
21#else
22 return __QNANL.ldouble_val;
23#endif
24}
25
lib/libc/musl/src/math/nan.c deleted-6
...@@ -1,6 +0,0 @@
1#include <math.h>
2
3double nan(const char *s)
4{
5 return NAN;
6}
lib/libc/musl/src/math/nanf.c deleted-6
...@@ -1,6 +0,0 @@
1#include <math.h>
2
3float nanf(const char *s)
4{
5 return NAN;
6}
lib/libc/musl/src/math/nanl.c deleted-6
...@@ -1,6 +0,0 @@
1#include <math.h>
2
3long double nanl(const char *s)
4{
5 return NAN;
6}
lib/libc/musl/src/stdlib/bsearch.c deleted-20
...@@ -1,20 +0,0 @@
1#include <stdlib.h>
2
3void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
4{
5 void *try;
6 int sign;
7 while (nel > 0) {
8 try = (char *)base + width*(nel/2);
9 sign = cmp(key, try);
10 if (sign < 0) {
11 nel /= 2;
12 } else if (sign > 0) {
13 base = (char *)try + width;
14 nel -= nel/2+1;
15 } else {
16 return try;
17 }
18 }
19 return NULL;
20}
src/libs/mingw.zig-3
...@@ -610,9 +610,6 @@ const mingw32_generic_src = [_][]const u8{...@@ -610,9 +610,6 @@ const mingw32_generic_src = [_][]const u8{
610 "gdtoa" ++ path.sep_str ++ "sum.c",610 "gdtoa" ++ path.sep_str ++ "sum.c",
611 "gdtoa" ++ path.sep_str ++ "ulp.c",611 "gdtoa" ++ path.sep_str ++ "ulp.c",
612 "math" ++ path.sep_str ++ "coshl.c",612 "math" ++ path.sep_str ++ "coshl.c",
613 "math" ++ path.sep_str ++ "fp_consts.c",
614 "math" ++ path.sep_str ++ "fp_constsf.c",
615 "math" ++ path.sep_str ++ "fp_constsl.c",
616 "math" ++ path.sep_str ++ "fpclassify.c",613 "math" ++ path.sep_str ++ "fpclassify.c",
617 "math" ++ path.sep_str ++ "fpclassifyf.c",614 "math" ++ path.sep_str ++ "fpclassifyf.c",
618 "math" ++ path.sep_str ++ "fpclassifyl.c",615 "math" ++ path.sep_str ++ "fpclassifyl.c",
src/libs/musl.zig-4
...@@ -1045,9 +1045,6 @@ const src_files = [_][]const u8{...@@ -1045,9 +1045,6 @@ const src_files = [_][]const u8{
1045 "musl/src/math/modf.c",1045 "musl/src/math/modf.c",
1046 "musl/src/math/modff.c",1046 "musl/src/math/modff.c",
1047 "musl/src/math/modfl.c",1047 "musl/src/math/modfl.c",
1048 "musl/src/math/nan.c",
1049 "musl/src/math/nanf.c",
1050 "musl/src/math/nanl.c",
1051 "musl/src/math/nearbyint.c",1048 "musl/src/math/nearbyint.c",
1052 "musl/src/math/nearbyintf.c",1049 "musl/src/math/nearbyintf.c",
1053 "musl/src/math/nearbyintl.c",1050 "musl/src/math/nearbyintl.c",
...@@ -1717,7 +1714,6 @@ const src_files = [_][]const u8{...@@ -1717,7 +1714,6 @@ const src_files = [_][]const u8{
1717 "musl/src/stdlib/atoi.c",1714 "musl/src/stdlib/atoi.c",
1718 "musl/src/stdlib/atol.c",1715 "musl/src/stdlib/atol.c",
1719 "musl/src/stdlib/atoll.c",1716 "musl/src/stdlib/atoll.c",
1720 "musl/src/stdlib/bsearch.c",
1721 "musl/src/stdlib/ecvt.c",1717 "musl/src/stdlib/ecvt.c",
1722 "musl/src/stdlib/fcvt.c",1718 "musl/src/stdlib/fcvt.c",
1723 "musl/src/stdlib/gcvt.c",1719 "musl/src/stdlib/gcvt.c",
src/libs/wasi_libc.zig-4
...@@ -818,9 +818,6 @@ const libc_top_half_src_files = [_][]const u8{...@@ -818,9 +818,6 @@ const libc_top_half_src_files = [_][]const u8{
818 "musl/src/math/modf.c",818 "musl/src/math/modf.c",
819 "musl/src/math/modff.c",819 "musl/src/math/modff.c",
820 "musl/src/math/modfl.c",820 "musl/src/math/modfl.c",
821 "musl/src/math/nan.c",
822 "musl/src/math/nanf.c",
823 "musl/src/math/nanl.c",
824 "musl/src/math/nearbyintl.c",821 "musl/src/math/nearbyintl.c",
825 "musl/src/math/nextafter.c",822 "musl/src/math/nextafter.c",
826 "musl/src/math/nextafterf.c",823 "musl/src/math/nextafterf.c",
...@@ -1007,7 +1004,6 @@ const libc_top_half_src_files = [_][]const u8{...@@ -1007,7 +1004,6 @@ const libc_top_half_src_files = [_][]const u8{
1007 "musl/src/stdlib/atoi.c",1004 "musl/src/stdlib/atoi.c",
1008 "musl/src/stdlib/atol.c",1005 "musl/src/stdlib/atol.c",
1009 "musl/src/stdlib/atoll.c",1006 "musl/src/stdlib/atoll.c",
1010 "musl/src/stdlib/bsearch.c",
1011 "musl/src/stdlib/ecvt.c",1007 "musl/src/stdlib/ecvt.c",
1012 "musl/src/stdlib/fcvt.c",1008 "musl/src/stdlib/fcvt.c",
1013 "musl/src/stdlib/gcvt.c",1009 "musl/src/stdlib/gcvt.c",