| author | |
| committer | |
| log | 245c160a7b97e1dc8e0fd04e706d7abb36ac9f0c |
| tree | d6f3b1fbcc1d43a3cd0a53933541a68d041e2b51 |
| parent | 811bada06d4d88d786119bab752c0e0cff345154 |
| signature |
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=<LIBC-TEST-PATH> -Dtest-filter=rintf -fqemu -fwasmtime --summary line
Build Summary: 1657/1657 steps succeeded
```8 files changed, 56 insertions(+), 97 deletions(-)
lib/c/math.zig+56-21| ... | ... | @@ -48,6 +48,10 @@ comptime { |
| 48 | 48 | symbol(&tanhf, "tanhf"); |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | if (builtin.target.isMinGW() or builtin.target.isMuslLibC()) { | |
| 52 | symbol(&rintf, "rintf"); | |
| 53 | } | |
| 54 | ||
| 51 | 55 | if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) { |
| 52 | 56 | symbol(&acos, "acos"); |
| 53 | 57 | symbol(&acosf, "acosf"); |
| ... | ... | @@ -348,7 +352,7 @@ fn pow10f(x: f32) callconv(.c) f32 { |
| 348 | 352 | } |
| 349 | 353 | |
| 350 | 354 | fn rint(x: f64) callconv(.c) f64 { |
| 351 | const toint: f64 = 1.0 / @as(f64, math.floatEps(f64)); | |
| 355 | const toint: f64 = 1.0 / math.floatEps(f64); | |
| 352 | 356 | const a: u64 = @bitCast(x); |
| 353 | 357 | const e = a >> 52 & 0x7ff; |
| 354 | 358 | const s = a >> 63; |
| ... | ... | @@ -368,39 +372,70 @@ fn rint(x: f64) callconv(.c) f64 { |
| 368 | 372 | return y; |
| 369 | 373 | } |
| 370 | 374 | |
| 371 | test "rint" { | |
| 375 | fn rintf(x: f32) callconv(.c) f32 { | |
| 376 | const toint: f32 = 1.0 / math.floatEps(f32); | |
| 377 | const a: u32 = @bitCast(x); | |
| 378 | const e = a >> 23 & 0xff; | |
| 379 | const s = a >> 31; | |
| 380 | var y: f32 = undefined; | |
| 381 | ||
| 382 | if (e >= 0x7f + 23) { | |
| 383 | return x; | |
| 384 | } | |
| 385 | ||
| 386 | if (s == 1) { | |
| 387 | y = x - toint + toint; | |
| 388 | } else { | |
| 389 | y = x + toint - toint; | |
| 390 | } | |
| 391 | ||
| 392 | if (y == 0) { | |
| 393 | return if (s == 1) -0.0 else 0; | |
| 394 | } | |
| 395 | return y; | |
| 396 | } | |
| 397 | ||
| 398 | fn testRint(comptime T: type) !void { | |
| 399 | const f = switch (T) { | |
| 400 | f32 => rintf, | |
| 401 | f64 => rint, | |
| 402 | else => @compileError("rint not implemented for" ++ @typeName(T)), | |
| 403 | }; | |
| 404 | ||
| 372 | 405 | // Positive numbers round correctly |
| 373 | try expectEqual(@as(f64, 42.0), rint(42.2)); | |
| 374 | try expectEqual(@as(f64, 42.0), rint(41.8)); | |
| 406 | try expectEqual(@as(T, 42.0), f(42.2)); | |
| 407 | try expectEqual(@as(T, 42.0), f(41.8)); | |
| 375 | 408 | |
| 376 | 409 | // Negative numbers round correctly |
| 377 | try expectEqual(@as(f64, -6.0), rint(-5.9)); | |
| 378 | try expectEqual(@as(f64, -6.0), rint(-6.1)); | |
| 410 | try expectEqual(@as(T, -6.0), f(-5.9)); | |
| 411 | try expectEqual(@as(T, -6.0), f(-6.1)); | |
| 379 | 412 | |
| 380 | 413 | // No rounding needed test |
| 381 | try expectEqual(@as(f64, 5.0), rint(5.0)); | |
| 382 | try expectEqual(@as(f64, -10.0), rint(-10.0)); | |
| 383 | try expectEqual(@as(f64, 0.0), rint(0.0)); | |
| 414 | try expectEqual(@as(T, 5.0), f(5.0)); | |
| 415 | try expectEqual(@as(T, -10.0), f(-10.0)); | |
| 416 | try expectEqual(@as(T, 0.0), f(0.0)); | |
| 384 | 417 | |
| 385 | 418 | // Very large numbers return unchanged |
| 386 | const large: f64 = 9007199254740992.0; // 2^53 | |
| 387 | try expectEqual(large, rint(large)); | |
| 388 | try expectEqual(-large, rint(-large)); | |
| 419 | const large: T = 9007199254740992.0; // 2^53 | |
| 420 | try expectEqual(large, f(large)); | |
| 421 | try expectEqual(-large, f(-large)); | |
| 389 | 422 | |
| 390 | 423 | // Small positive numbers round to zero |
| 391 | const pos_result = rint(0.3); | |
| 392 | try expectEqual(@as(f64, 0.0), pos_result); | |
| 393 | try expect(@as(u64, @bitCast(pos_result)) == 0); | |
| 424 | const pos_result = f(0.3); | |
| 425 | try expect(math.isPositiveZero(pos_result)); | |
| 394 | 426 | |
| 395 | 427 | // Small negative numbers round to negative zero |
| 396 | const neg_result = rint(-0.3); | |
| 397 | try expectEqual(@as(f64, 0.0), neg_result); | |
| 398 | const bits: u64 = @bitCast(neg_result); | |
| 399 | try expect((bits >> 63) == 1); | |
| 428 | const neg_result = f(-0.3); | |
| 429 | try expect(math.isNegativeZero(neg_result)); | |
| 400 | 430 | |
| 401 | 431 | // Exact half rounds to nearest even (banker's rounding) |
| 402 | try expectEqual(@as(f64, 2.0), rint(2.5)); | |
| 403 | try expectEqual(@as(f64, 4.0), rint(3.5)); | |
| 432 | try expectEqual(@as(T, 2.0), f(2.5)); | |
| 433 | try expectEqual(@as(T, 4.0), f(3.5)); | |
| 434 | } | |
| 435 | ||
| 436 | test "rint" { | |
| 437 | try testRint(f32); | |
| 438 | try testRint(f64); | |
| 404 | 439 | } |
| 405 | 440 | |
| 406 | 441 | fn tanh(x: f64) callconv(.c) f64 { |
lib/libc/mingw/math/arm64/rintf.c deleted-12| ... | ... | @@ -1,12 +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 <math.h> | |
| 7 | ||
| 8 | float rintf (float x) { | |
| 9 | float retval = 0.0F; | |
| 10 | __asm__ __volatile__ ("frintx %s0, %s1\n\t" : "=w" (retval) : "w" (x)); | |
| 11 | return retval; | |
| 12 | } |
lib/libc/musl/src/math/aarch64/rintf.c deleted-7| ... | ... | @@ -1,7 +0,0 @@ |
| 1 | #include <math.h> | |
| 2 | ||
| 3 | float rintf(float x) | |
| 4 | { | |
| 5 | 	__asm__ ("frintx %s0, %s1" : "=w"(x) : "w"(x)); | |
| 6 | 	return x; | |
| 7 | } |
lib/libc/musl/src/math/i386/rintf.c deleted-7| ... | ... | @@ -1,7 +0,0 @@ |
| 1 | #include <math.h> | |
| 2 | ||
| 3 | float rintf(float x) | |
| 4 | { | |
| 5 | 	__asm__ ("frndint" : "+t"(x)); | |
| 6 | 	return x; | |
| 7 | } |
lib/libc/musl/src/math/rintf.c deleted-30| ... | ... | @@ -1,30 +0,0 @@ |
| 1 | #include <float.h> | |
| 2 | #include <math.h> | |
| 3 | #include <stdint.h> | |
| 4 | ||
| 5 | #if FLT_EVAL_METHOD==0 | |
| 6 | #define EPS FLT_EPSILON | |
| 7 | #elif FLT_EVAL_METHOD==1 | |
| 8 | #define EPS DBL_EPSILON | |
| 9 | #elif FLT_EVAL_METHOD==2 | |
| 10 | #define EPS LDBL_EPSILON | |
| 11 | #endif | |
| 12 | static const float_t toint = 1/EPS; | |
| 13 | ||
| 14 | float rintf(float x) | |
| 15 | { | |
| 16 | 	union {float f; uint32_t i;} u = {x}; | |
| 17 | 	int e = u.i>>23 & 0xff; | |
| 18 | 	int s = u.i>>31; | |
| 19 | 	float_t y; | |
| 20 | ||
| 21 | 	if (e >= 0x7f+23) | |
| 22 | 		return x; | |
| 23 | 	if (s) | |
| 24 | 		y = x - toint + toint; | |
| 25 | 	else | |
| 26 | 		y = x + toint - toint; | |
| 27 | 	if (y == 0) | |
| 28 | 		return s ? -0.0f : 0.0f; | |
| 29 | 	return y; | |
| 30 | } |
lib/libc/musl/src/math/s390x/rintf.c deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | #include <math.h> | |
| 2 | ||
| 3 | #if defined(__HTM__) || __ARCH__ >= 9 | |
| 4 | ||
| 5 | float rintf(float x) | |
| 6 | { | |
| 7 | 	__asm__ ("fiebr %0, 0, %1" : "=f"(x) : "f"(x)); | |
| 8 | 	return x; | |
| 9 | } | |
| 10 | ||
| 11 | #else | |
| 12 | ||
| 13 | #include "../rintf.c" | |
| 14 | ||
| 15 | #endif |
src/libs/mingw.zig-1| ... | ... | @@ -996,7 +996,6 @@ const mingw32_arm32_src = [_][]const u8{ |
| 996 | 996 | const mingw32_arm64_src = [_][]const u8{ |
| 997 | 997 | // mingwex |
| 998 | 998 | "math" ++ path.sep_str ++ "arm64" ++ path.sep_str ++ "rint.c", |
| 999 | "math" ++ path.sep_str ++ "arm64" ++ path.sep_str ++ "rintf.c", | |
| 1000 | 999 | "math" ++ path.sep_str ++ "arm64" ++ path.sep_str ++ "sincos.S", |
| 1001 | 1000 | }; |
| 1002 | 1001 |
src/libs/musl.zig-4| ... | ... | @@ -792,7 +792,6 @@ const src_files = [_][]const u8{ |
| 792 | 792 | "musl/src/math/aarch64/lroundf.c", |
| 793 | 793 | "musl/src/math/aarch64/nearbyint.c", |
| 794 | 794 | "musl/src/math/aarch64/nearbyintf.c", |
| 795 | "musl/src/math/aarch64/rintf.c", | |
| 796 | 795 | "musl/src/math/acosh.c", |
| 797 | 796 | "musl/src/math/acoshl.c", |
| 798 | 797 | "musl/src/math/acosl.c", |
| ... | ... | @@ -867,7 +866,6 @@ const src_files = [_][]const u8{ |
| 867 | 866 | "musl/src/math/i386/remquof.s", |
| 868 | 867 | "musl/src/math/i386/remquol.s", |
| 869 | 868 | "musl/src/math/i386/remquo.s", |
| 870 | "musl/src/math/i386/rintf.c", | |
| 871 | 869 | "musl/src/math/i386/rintl.c", |
| 872 | 870 | "musl/src/math/i386/scalblnf.s", |
| 873 | 871 | "musl/src/math/i386/scalblnl.s", |
| ... | ... | @@ -955,7 +953,6 @@ const src_files = [_][]const u8{ |
| 955 | 953 | "musl/src/math/remquo.c", |
| 956 | 954 | "musl/src/math/remquof.c", |
| 957 | 955 | "musl/src/math/remquol.c", |
| 958 | "musl/src/math/rintf.c", | |
| 959 | 956 | "musl/src/math/rintl.c", |
| 960 | 957 | "musl/src/math/riscv32/fma.c", |
| 961 | 958 | "musl/src/math/riscv32/fmaf.c", |
| ... | ... | @@ -966,7 +963,6 @@ const src_files = [_][]const u8{ |
| 966 | 963 | "musl/src/math/s390x/nearbyint.c", |
| 967 | 964 | "musl/src/math/s390x/nearbyintf.c", |
| 968 | 965 | "musl/src/math/s390x/nearbyintl.c", |
| 969 | "musl/src/math/s390x/rintf.c", | |
| 970 | 966 | "musl/src/math/s390x/rintl.c", |
| 971 | 967 | "musl/src/math/scalb.c", |
| 972 | 968 | "musl/src/math/scalbf.c", |