libzigc: hypot (#31104)

First time contribution.

Implements hypot for libzigc #30978.

Commands i run:
```
$ stage3/bin/zig build -p stage4 -Denable-llvm -Dno-lib

$ stage4/bin/zig build test-libc -Dlibc-test-path=../../libc-test -Dtest-filter=hypot --summary line -fqemu -fwasmtime
Build Summary: 725/737 steps succeeded (12 skipped)
```

I also changed std.math.hypot becuase some libc-tests raised fp exceptions. Example:
```
../../libc-test/src/math/special/hypot.h:8: bad fp exception: RN hypot(0x1p-1074,0x0p+0)=0x1p-1074, want 0 got INEXACT|UNDERFLOW
../../libc-test/src/math/special/hypot.h:9: bad fp exception: RN hypot(0x1p-1074,-0x0p+0)=0x1p-1074, want 0 got INEXACT|UNDERFLOW
```

I also run this command as a quick sanity check:
```
$ stage4/bin/zig build test-std -Dtest-filter=hypot -Dtest-target-filter=x86_64-linux-musl --summary line
Build Summary: 5/5 steps succeeded; 136/136 tests passed
```

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31104
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
Co-authored-by: Pivok <pivoc@protonmail.com>
Co-committed-by: Pivok <pivoc@protonmail.com>
This commit is contained in:
Pivok
2026-02-05 21:57:32 +01:00
committed by Andrew Kelley
parent c38f9336a3
commit d0b39c7f2b
6 changed files with 9 additions and 119 deletions
+5
View File
@@ -41,6 +41,7 @@ comptime {
@export(&atanl, .{ .name = "atanl", .linkage = common.linkage, .visibility = common.visibility });
@export(&cbrt, .{ .name = "cbrt", .linkage = common.linkage, .visibility = common.visibility });
@export(&cbrtf, .{ .name = "cbrtf", .linkage = common.linkage, .visibility = common.visibility });
@export(&hypot, .{ .name = "hypot", .linkage = common.linkage, .visibility = common.visibility });
@export(&pow, .{ .name = "pow", .linkage = common.linkage, .visibility = common.visibility });
}
@@ -118,6 +119,10 @@ fn cbrtf(x: f32) callconv(.c) f32 {
return math.cbrt(x);
}
fn hypot(x: f64, y: f64) callconv(.c) f64 {
return math.hypot(x, y);
}
fn pow(x: f64, y: f64) callconv(.c) f64 {
return math.pow(f64, x, y);
}
-67
View File
@@ -1,67 +0,0 @@
#include <math.h>
#include <stdint.h>
#include <float.h>
#if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64
#define SPLIT (0x1p32 + 1)
#else
#define SPLIT (0x1p27 + 1)
#endif
static void sq(double_t *hi, double_t *lo, double x)
{
double_t xh, xl, xc;
xc = (double_t)x*SPLIT;
xh = x - xc + xc;
xl = x - xh;
*hi = (double_t)x*x;
*lo = xh*xh - *hi + 2*xh*xl + xl*xl;
}
double hypot(double x, double y)
{
union {double f; uint64_t i;} ux = {x}, uy = {y}, ut;
int ex, ey;
double_t hx, lx, hy, ly, z;
/* arrange |x| >= |y| */
ux.i &= -1ULL>>1;
uy.i &= -1ULL>>1;
if (ux.i < uy.i) {
ut = ux;
ux = uy;
uy = ut;
}
/* special cases */
ex = ux.i>>52;
ey = uy.i>>52;
x = ux.f;
y = uy.f;
/* note: hypot(inf,nan) == inf */
if (ey == 0x7ff)
return y;
if (ex == 0x7ff || uy.i == 0)
return x;
/* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */
/* 64 difference is enough for ld80 double_t */
if (ex - ey > 64)
return x + y;
/* precise sqrt argument in nearest rounding mode without overflow */
/* xh*xh must not overflow and xl*xl must not underflow in sq */
z = 1;
if (ex > 0x3ff+510) {
z = 0x1p700;
x *= 0x1p-700;
y *= 0x1p-700;
} else if (ey < 0x3ff-450) {
z = 0x1p-700;
x *= 0x1p700;
y *= 0x1p700;
}
sq(&hx, &lx, x);
sq(&hy, &ly, y);
return z*sqrt(ly+lx+hy+hx);
}
-45
View File
@@ -1,45 +0,0 @@
.global hypot
.type hypot,@function
hypot:
mov 8(%esp),%eax
mov 16(%esp),%ecx
add %eax,%eax
add %ecx,%ecx
and %eax,%ecx
cmp $0xffe00000,%ecx
jae 2f
or 4(%esp),%eax
jnz 1f
fldl 12(%esp)
fabs
ret
1: mov 16(%esp),%eax
add %eax,%eax
or 12(%esp),%eax
jnz 1f
fldl 4(%esp)
fabs
ret
1: fldl 4(%esp)
fld %st(0)
fmulp
fldl 12(%esp)
fld %st(0)
fmulp
faddp
fsqrt
ret
2: sub $0xffe00000,%eax
or 4(%esp),%eax
jnz 1f
fldl 4(%esp)
fabs
ret
1: mov 16(%esp),%eax
add %eax,%eax
sub $0xffe00000,%eax
or 12(%esp),%eax
fldl 12(%esp)
jnz 1f
fabs
1: ret
+4 -4
View File
@@ -6,10 +6,10 @@ const isNan = math.isNan;
const isInf = math.isInf;
const inf = math.inf;
const nan = math.nan;
const floatEpsAt = math.floatEpsAt;
const floatEps = math.floatEps;
const floatMin = math.floatMin;
const floatMax = math.floatMax;
const floatTrueMin = math.floatTrueMin;
/// Returns sqrt(x * x + y * y), avoiding unnecessary overflow and underflow.
///
@@ -30,8 +30,7 @@ pub fn hypot(x: anytype, y: anytype) @TypeOf(x, y) {
}
const lower = @sqrt(floatMin(T));
const upper = @sqrt(floatMax(T) / 2);
const incre = @sqrt(floatEps(T) / 2);
const scale = floatEpsAt(T, incre);
const scale = floatTrueMin(T) * upper;
const hypfn = if (emulateFma(T)) hypotUnfused else hypotFused;
var major: T = x;
var minor: T = y;
@@ -46,7 +45,8 @@ pub fn hypot(x: anytype, y: anytype) @TypeOf(x, y) {
major = minor;
minor = tempo;
}
if (major * incre >= minor) return major;
if (minor == 0.0) return major;
if (major - minor == major) return major;
if (major > upper) return hypfn(T, major * scale, minor * scale) / scale;
if (minor < lower) return hypfn(T, major / scale, minor / scale) * scale;
return hypfn(T, major, minor);
-2
View File
@@ -874,7 +874,6 @@ const src_files = [_][]const u8{
"musl/src/math/frexp.c",
"musl/src/math/frexpf.c",
"musl/src/math/frexpl.c",
"musl/src/math/hypot.c",
"musl/src/math/hypotf.c",
"musl/src/math/hypotl.c",
"musl/src/math/i386/acosf.s",
@@ -890,7 +889,6 @@ const src_files = [_][]const u8{
"musl/src/math/i386/expl.s",
"musl/src/math/i386/expm1l.s",
"musl/src/math/i386/hypotf.s",
"musl/src/math/i386/hypot.s",
"musl/src/math/i386/__invtrigl.s",
"musl/src/math/i386/ldexpf.s",
"musl/src/math/i386/ldexpl.s",
-1
View File
@@ -730,7 +730,6 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/math/frexp.c",
"musl/src/math/frexpf.c",
"musl/src/math/frexpl.c",
"musl/src/math/hypot.c",
"musl/src/math/hypotf.c",
"musl/src/math/hypotl.c",
"musl/src/math/ilogb.c",