From 245c160a7b97e1dc8e0fd04e706d7abb36ac9f0c Mon Sep 17 00:00:00 2001 From: mihael Date: Fri, 20 Mar 2026 20:14:25 +0100 Subject: [PATCH] `libzigc/math`: Implement `rintf` The implementation was ported from `musl` to Zig code, and the `rint` unit tests were generalized so they could be used for `rintf` as well. This was checked both through unit tests and running `libc-test` suite: ``` $ ./build/stage3/bin/zig build -p stage4 -Denable-llvm -Dno-lib $ stage4/bin/zig build test-libc -Dlibc-test-path= -Dtest-filter=rintf -fqemu -fwasmtime --summary line Build Summary: 1657/1657 steps succeeded ``` --- lib/c/math.zig | 77 +++++++++++++++++++------- lib/libc/mingw/math/arm64/rintf.c | 12 ---- lib/libc/musl/src/math/aarch64/rintf.c | 7 --- lib/libc/musl/src/math/i386/rintf.c | 7 --- lib/libc/musl/src/math/rintf.c | 30 ---------- lib/libc/musl/src/math/s390x/rintf.c | 15 ----- src/libs/mingw.zig | 1 - src/libs/musl.zig | 4 -- 8 files changed, 56 insertions(+), 97 deletions(-) delete mode 100644 lib/libc/mingw/math/arm64/rintf.c delete mode 100644 lib/libc/musl/src/math/aarch64/rintf.c delete mode 100644 lib/libc/musl/src/math/i386/rintf.c delete mode 100644 lib/libc/musl/src/math/rintf.c delete mode 100644 lib/libc/musl/src/math/s390x/rintf.c diff --git a/lib/c/math.zig b/lib/c/math.zig index d3578d75dd35060a6bdf709b568ebc8f18fbbc46..582c7232c8e05d1ac4fba803d087ed9457df6486 100644 --- a/lib/c/math.zig +++ b/lib/c/math.zig @@ -48,6 +48,10 @@ comptime { symbol(&tanhf, "tanhf"); } + if (builtin.target.isMinGW() or builtin.target.isMuslLibC()) { + symbol(&rintf, "rintf"); + } + if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) { symbol(&acos, "acos"); symbol(&acosf, "acosf"); @@ -348,7 +352,7 @@ fn pow10f(x: f32) callconv(.c) f32 { } fn rint(x: f64) callconv(.c) f64 { - const toint: f64 = 1.0 / @as(f64, math.floatEps(f64)); + const toint: f64 = 1.0 / math.floatEps(f64); const a: u64 = @bitCast(x); const e = a >> 52 & 0x7ff; const s = a >> 63; @@ -368,39 +372,70 @@ fn rint(x: f64) callconv(.c) f64 { return y; } -test "rint" { +fn rintf(x: f32) callconv(.c) f32 { + const toint: f32 = 1.0 / math.floatEps(f32); + const a: u32 = @bitCast(x); + const e = a >> 23 & 0xff; + const s = a >> 31; + var y: f32 = undefined; + + if (e >= 0x7f + 23) { + return x; + } + + if (s == 1) { + y = x - toint + toint; + } else { + y = x + toint - toint; + } + + if (y == 0) { + return if (s == 1) -0.0 else 0; + } + return y; +} + +fn testRint(comptime T: type) !void { + const f = switch (T) { + f32 => rintf, + f64 => rint, + else => @compileError("rint not implemented for" ++ @typeName(T)), + }; + // Positive numbers round correctly - try expectEqual(@as(f64, 42.0), rint(42.2)); - try expectEqual(@as(f64, 42.0), rint(41.8)); + try expectEqual(@as(T, 42.0), f(42.2)); + try expectEqual(@as(T, 42.0), f(41.8)); // Negative numbers round correctly - try expectEqual(@as(f64, -6.0), rint(-5.9)); - try expectEqual(@as(f64, -6.0), rint(-6.1)); + try expectEqual(@as(T, -6.0), f(-5.9)); + try expectEqual(@as(T, -6.0), f(-6.1)); // No rounding needed test - try expectEqual(@as(f64, 5.0), rint(5.0)); - try expectEqual(@as(f64, -10.0), rint(-10.0)); - try expectEqual(@as(f64, 0.0), rint(0.0)); + try expectEqual(@as(T, 5.0), f(5.0)); + try expectEqual(@as(T, -10.0), f(-10.0)); + try expectEqual(@as(T, 0.0), f(0.0)); // Very large numbers return unchanged - const large: f64 = 9007199254740992.0; // 2^53 - try expectEqual(large, rint(large)); - try expectEqual(-large, rint(-large)); + const large: T = 9007199254740992.0; // 2^53 + try expectEqual(large, f(large)); + try expectEqual(-large, f(-large)); // Small positive numbers round to zero - const pos_result = rint(0.3); - try expectEqual(@as(f64, 0.0), pos_result); - try expect(@as(u64, @bitCast(pos_result)) == 0); + const pos_result = f(0.3); + try expect(math.isPositiveZero(pos_result)); // Small negative numbers round to negative zero - const neg_result = rint(-0.3); - try expectEqual(@as(f64, 0.0), neg_result); - const bits: u64 = @bitCast(neg_result); - try expect((bits >> 63) == 1); + const neg_result = f(-0.3); + try expect(math.isNegativeZero(neg_result)); // Exact half rounds to nearest even (banker's rounding) - try expectEqual(@as(f64, 2.0), rint(2.5)); - try expectEqual(@as(f64, 4.0), rint(3.5)); + try expectEqual(@as(T, 2.0), f(2.5)); + try expectEqual(@as(T, 4.0), f(3.5)); +} + +test "rint" { + try testRint(f32); + try testRint(f64); } fn tanh(x: f64) callconv(.c) f64 { diff --git a/lib/libc/mingw/math/arm64/rintf.c b/lib/libc/mingw/math/arm64/rintf.c deleted file mode 100644 index 914769a1df063f29b89c8efa9a8a2caa46ae897b..0000000000000000000000000000000000000000 --- a/lib/libc/mingw/math/arm64/rintf.c +++ /dev/null @@ -1,12 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the mingw-w64 runtime package. - * No warranty is given; refer to the file DISCLAIMER.PD within this package. - */ -#include - -float rintf (float x) { - float retval = 0.0F; - __asm__ __volatile__ ("frintx %s0, %s1\n\t" : "=w" (retval) : "w" (x)); - return retval; -} diff --git a/lib/libc/musl/src/math/aarch64/rintf.c b/lib/libc/musl/src/math/aarch64/rintf.c deleted file mode 100644 index 1ae7dd254003946c1aa79eafe90b00e218a44f94..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/aarch64/rintf.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -float rintf(float x) -{ - __asm__ ("frintx %s0, %s1" : "=w"(x) : "w"(x)); - return x; -} diff --git a/lib/libc/musl/src/math/i386/rintf.c b/lib/libc/musl/src/math/i386/rintf.c deleted file mode 100644 index bb4121a4e61ce899fa1cf9d2e879eaf26785f468..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/i386/rintf.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -float rintf(float x) -{ - __asm__ ("frndint" : "+t"(x)); - return x; -} diff --git a/lib/libc/musl/src/math/rintf.c b/lib/libc/musl/src/math/rintf.c deleted file mode 100644 index 9047688d246a69c2698ce27399135e1db7ac2f65..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/rintf.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -#if FLT_EVAL_METHOD==0 -#define EPS FLT_EPSILON -#elif FLT_EVAL_METHOD==1 -#define EPS DBL_EPSILON -#elif FLT_EVAL_METHOD==2 -#define EPS LDBL_EPSILON -#endif -static const float_t toint = 1/EPS; - -float rintf(float x) -{ - union {float f; uint32_t i;} u = {x}; - int e = u.i>>23 & 0xff; - int s = u.i>>31; - float_t y; - - if (e >= 0x7f+23) - return x; - if (s) - y = x - toint + toint; - else - y = x + toint - toint; - if (y == 0) - return s ? -0.0f : 0.0f; - return y; -} diff --git a/lib/libc/musl/src/math/s390x/rintf.c b/lib/libc/musl/src/math/s390x/rintf.c deleted file mode 100644 index c9f13130cf9f40164be3b5ee6d38375aca696eec..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/s390x/rintf.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#if defined(__HTM__) || __ARCH__ >= 9 - -float rintf(float x) -{ - __asm__ ("fiebr %0, 0, %1" : "=f"(x) : "f"(x)); - return x; -} - -#else - -#include "../rintf.c" - -#endif diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 254f0e56212c86658317698ce493958291cc823d..2a3c858030e7b1f1e7f58f71f6262fecf01be14d 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -996,7 +996,6 @@ const mingw32_arm32_src = [_][]const u8{ const mingw32_arm64_src = [_][]const u8{ // mingwex "math" ++ path.sep_str ++ "arm64" ++ path.sep_str ++ "rint.c", - "math" ++ path.sep_str ++ "arm64" ++ path.sep_str ++ "rintf.c", "math" ++ path.sep_str ++ "arm64" ++ path.sep_str ++ "sincos.S", }; diff --git a/src/libs/musl.zig b/src/libs/musl.zig index e7548b16983c19b7f3be9f1cd57b0228a72338d0..e325efd931f61954b68142082cbb96a3d9b7ff24 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -792,7 +792,6 @@ const src_files = [_][]const u8{ "musl/src/math/aarch64/lroundf.c", "musl/src/math/aarch64/nearbyint.c", "musl/src/math/aarch64/nearbyintf.c", - "musl/src/math/aarch64/rintf.c", "musl/src/math/acosh.c", "musl/src/math/acoshl.c", "musl/src/math/acosl.c", @@ -867,7 +866,6 @@ const src_files = [_][]const u8{ "musl/src/math/i386/remquof.s", "musl/src/math/i386/remquol.s", "musl/src/math/i386/remquo.s", - "musl/src/math/i386/rintf.c", "musl/src/math/i386/rintl.c", "musl/src/math/i386/scalblnf.s", "musl/src/math/i386/scalblnl.s", @@ -955,7 +953,6 @@ const src_files = [_][]const u8{ "musl/src/math/remquo.c", "musl/src/math/remquof.c", "musl/src/math/remquol.c", - "musl/src/math/rintf.c", "musl/src/math/rintl.c", "musl/src/math/riscv32/fma.c", "musl/src/math/riscv32/fmaf.c", @@ -966,7 +963,6 @@ const src_files = [_][]const u8{ "musl/src/math/s390x/nearbyint.c", "musl/src/math/s390x/nearbyintf.c", "musl/src/math/s390x/nearbyintl.c", - "musl/src/math/s390x/rintf.c", "musl/src/math/s390x/rintl.c", "musl/src/math/scalb.c", "musl/src/math/scalbf.c", -- 2.54.0