authorgravatar for hi@mihaelm.commihael <hi@mihaelm.com> 2026-03-18 20:32:18+01:00
committergravatar for hi@mihaelm.commihael <hi@mihaelm.com> 2026-04-02 23:54:19+02:00
logdcffee067290c03f89c5afcacab1ba543ee28e7c
tree6ad4837f6be1f73f68b938750a526196ea0c25e3
parentba4af7aa8a33d19bbf7b0225a2d1407d5a756c06
signaturebadge-check Signed by SSH key SHA256:aoFoShdYLdrqMichqKXSSieTKUfACUIDJHsKc4V2tQg

`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=<LIBC-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.

4 files changed, 20 insertions(+), 25 deletions(-)

lib/c/math.zig+20
......@@ -60,6 +60,7 @@ comptime {
6060 symbol(&exp10, "exp10");
6161 symbol(&exp10f, "exp10f");
6262 symbol(&fdim, "fdim");
63 symbol(&frexp, "frexp");
6364 symbol(&hypot, "hypot");
6465 symbol(&modf, "modf");
6566 symbol(&pow, "pow");
......@@ -161,6 +162,25 @@ fn fdim(x: f64, y: f64) callconv(.c) f64 {
161162 return 0;
162163}
163164
165fn frexp(x: f64, e: *c_int) callconv(.c) f64 {
166 // libc expects `*e` to be unspecified in this case; an unspecified C value
167 // should be a valid value of the relevant type, yet Zig's std
168 // implementation sets it to `undefined` -- which can even be nonsense
169 // according to the type (int). Therefore, we're setting it to a valid
170 // int value in Zig -- a zero.
171 //
172 // This mirrors the handling of infinities, where libc also expects
173 // unspecified for the value `*e` and Zig std sets it to a zero.
174 if (math.isNan(x)) {
175 e.* = 0;
176 return x;
177 }
178
179 const r = math.frexp(x);
180 e.* = r.exponent;
181 return r.significand;
182}
183
164184fn hypot(x: f64, y: f64) callconv(.c) f64 {
165185 return math.hypot(x, y);
166186}
lib/libc/musl/src/math/frexp.c deleted-23
......@@ -1,23 +0,0 @@
1#include <math.h>
2#include <stdint.h>
3
4double frexp(double x, int *e)
5{
6 union { double d; uint64_t i; } y = { x };
7 int ee = y.i>>52 & 0x7ff;
8
9 if (!ee) {
10 if (x) {
11 x = frexp(x*0x1p64, e);
12 *e -= 64;
13 } else *e = 0;
14 return x;
15 } else if (ee == 0x7ff) {
16 return x;
17 }
18
19 *e = ee - 0x3fe;
20 y.i &= 0x800fffffffffffffull;
21 y.i |= 0x3fe0000000000000ull;
22 return y.d;
23}
src/libs/musl.zig-1
......@@ -839,7 +839,6 @@ const src_files = [_][]const u8{
839839 "musl/src/math/__fpclassify.c",
840840 "musl/src/math/__fpclassifyf.c",
841841 "musl/src/math/__fpclassifyl.c",
842 "musl/src/math/frexp.c",
843842 "musl/src/math/frexpf.c",
844843 "musl/src/math/frexpl.c",
845844 "musl/src/math/i386/acosl.s",
src/libs/wasi_libc.zig-1
......@@ -701,7 +701,6 @@ const libc_top_half_src_files = [_][]const u8{
701701 "musl/src/math/finitef.c",
702702 "musl/src/math/fma.c",
703703 "musl/src/math/fmaf.c",
704 "musl/src/math/frexp.c",
705704 "musl/src/math/frexpf.c",
706705 "musl/src/math/frexpl.c",
707706 "musl/src/math/ilogb.c",