From dcffee067290c03f89c5afcacab1ba543ee28e7c Mon Sep 17 00:00:00 2001 From: mihael Date: Wed, 18 Mar 2026 20:32:18 +0100 Subject: [PATCH] `libzigc/math`: Implement `frexp` The changes were tested by running: ``` $ ./build/stage3/bin/zig build -p stage4 -Denable-llvm -Dno-lib $ stage4/bin/zig build test-libc -Dlibc-test-path= -Dtest-filter=frexp -fqemu -fwasmtime --summary line Build Summary: 737/737 steps succeeded ``` The tests were passing even when it was a straightforward calling of Zig std library, but I wanted the `x is NaN` special case to match the behaviour described in `libc` manpages, and for it to be consistent with how infinities as arguments are handled in Zig. --- lib/c/math.zig | 20 ++++++++++++++++++++ lib/libc/musl/src/math/frexp.c | 23 ----------------------- src/libs/musl.zig | 1 - src/libs/wasi_libc.zig | 1 - 4 files changed, 20 insertions(+), 25 deletions(-) delete mode 100644 lib/libc/musl/src/math/frexp.c diff --git a/lib/c/math.zig b/lib/c/math.zig index 5b191c3e93..8fe93716db 100644 --- a/lib/c/math.zig +++ b/lib/c/math.zig @@ -60,6 +60,7 @@ comptime { symbol(&exp10, "exp10"); symbol(&exp10f, "exp10f"); symbol(&fdim, "fdim"); + symbol(&frexp, "frexp"); symbol(&hypot, "hypot"); symbol(&modf, "modf"); symbol(&pow, "pow"); @@ -161,6 +162,25 @@ fn fdim(x: f64, y: f64) callconv(.c) f64 { return 0; } +fn frexp(x: f64, e: *c_int) callconv(.c) f64 { + // libc expects `*e` to be unspecified in this case; an unspecified C value + // should be a valid value of the relevant type, yet Zig's std + // implementation sets it to `undefined` -- which can even be nonsense + // according to the type (int). Therefore, we're setting it to a valid + // int value in Zig -- a zero. + // + // This mirrors the handling of infinities, where libc also expects + // unspecified for the value `*e` and Zig std sets it to a zero. + if (math.isNan(x)) { + e.* = 0; + return x; + } + + const r = math.frexp(x); + e.* = r.exponent; + return r.significand; +} + fn hypot(x: f64, y: f64) callconv(.c) f64 { return math.hypot(x, y); } diff --git a/lib/libc/musl/src/math/frexp.c b/lib/libc/musl/src/math/frexp.c deleted file mode 100644 index 27b6266ed0..0000000000 --- a/lib/libc/musl/src/math/frexp.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -double frexp(double x, int *e) -{ - union { double d; uint64_t i; } y = { x }; - int ee = y.i>>52 & 0x7ff; - - if (!ee) { - if (x) { - x = frexp(x*0x1p64, e); - *e -= 64; - } else *e = 0; - return x; - } else if (ee == 0x7ff) { - return x; - } - - *e = ee - 0x3fe; - y.i &= 0x800fffffffffffffull; - y.i |= 0x3fe0000000000000ull; - return y.d; -} diff --git a/src/libs/musl.zig b/src/libs/musl.zig index a3806437d7..e90a08f92c 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -839,7 +839,6 @@ const src_files = [_][]const u8{ "musl/src/math/__fpclassify.c", "musl/src/math/__fpclassifyf.c", "musl/src/math/__fpclassifyl.c", - "musl/src/math/frexp.c", "musl/src/math/frexpf.c", "musl/src/math/frexpl.c", "musl/src/math/i386/acosl.s", diff --git a/src/libs/wasi_libc.zig b/src/libs/wasi_libc.zig index aaf8968060..d694a0381e 100644 --- a/src/libs/wasi_libc.zig +++ b/src/libs/wasi_libc.zig @@ -701,7 +701,6 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/math/finitef.c", "musl/src/math/fma.c", "musl/src/math/fmaf.c", - "musl/src/math/frexp.c", "musl/src/math/frexpf.c", "musl/src/math/frexpl.c", "musl/src/math/ilogb.c",