mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-05-21 16:41:56 +03:00
libzigc: implement modff
`modf` function was generalized and renamed to `modfGeneric`, `modf` and `modff` provide the appropriate type while calling that function. The unit tests were also generalized so they can be reused for different float types. Both `modf` and `modff` were tested after making these changes: ``` $ stage4/bin/zig build test-libc -Dlibc-test-path=<LIBC-TEST-PATH> -Dtest-filter=modf -fqemu -fwasmtime --summary line Build Summary: 921/921 steps succeeded ``` ``` stage4/bin/zig build test-libc -Dlibc-test-path=<LIBC-TEST-PATH> -Dtest-filter=modff -fqemu -fwasmtime --summary line Build Summary: 369/369 steps succeeded ```
This commit is contained in:
+44
-20
@@ -4,6 +4,7 @@ const std = @import("std");
|
||||
const math = std.math;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const expectApproxEqAbs = std.testing.expectApproxEqAbs;
|
||||
const expectApproxEqRel = std.testing.expectApproxEqRel;
|
||||
|
||||
const symbol = @import("../c.zig").symbol;
|
||||
@@ -37,6 +38,7 @@ comptime {
|
||||
symbol(&coshf, "coshf");
|
||||
symbol(&hypotf, "hypotf");
|
||||
symbol(&hypotl, "hypotl");
|
||||
symbol(&modff, "modff");
|
||||
symbol(&nan, "nan");
|
||||
symbol(&nanf, "nanf");
|
||||
symbol(&nanl, "nanl");
|
||||
@@ -166,66 +168,88 @@ fn isnanl(x: c_longdouble) callconv(.c) c_int {
|
||||
return if (math.isNan(x)) 1 else 0;
|
||||
}
|
||||
|
||||
fn modf(x: f64, iptr: *f64) callconv(.c) f64 {
|
||||
fn modfGeneric(comptime T: type, x: T, iptr: *T) T {
|
||||
if (math.isNegativeInf(x)) {
|
||||
iptr.* = -math.inf(f64);
|
||||
iptr.* = -math.inf(T);
|
||||
return -0.0;
|
||||
}
|
||||
|
||||
if (math.isPositiveInf(x)) {
|
||||
iptr.* = math.inf(f64);
|
||||
iptr.* = math.inf(T);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Avoids raising the INVALID flag on qemu-riscv
|
||||
if (math.isNan(x)) {
|
||||
iptr.* = math.nan(f64);
|
||||
return math.nan(f64);
|
||||
iptr.* = math.nan(T);
|
||||
return math.nan(T);
|
||||
}
|
||||
|
||||
const r = math.modf(x);
|
||||
iptr.* = r.ipart;
|
||||
|
||||
// If the result would be a negative zero, we must be explicit about
|
||||
// If the result is a negative zero, we must be explicit about
|
||||
// returning a negative zero.
|
||||
return if (math.isNegativeZero(x) or (x < 0.0 and x == r.ipart)) -0.0 else r.fpart;
|
||||
}
|
||||
|
||||
test "modf" {
|
||||
var int: f64 = undefined;
|
||||
const iptr = ∫
|
||||
const eps_val = 1e-6;
|
||||
fn modf(x: f64, iptr: *f64) callconv(.c) f64 {
|
||||
return modfGeneric(f64, x, iptr);
|
||||
}
|
||||
|
||||
const normal_frac = modf(1234.5678, iptr);
|
||||
try expectApproxEqRel(0.5678, normal_frac, eps_val);
|
||||
try expectApproxEqRel(1234.0, iptr.*, eps_val);
|
||||
fn modff(x: f32, iptr: *f32) callconv(.c) f32 {
|
||||
return modfGeneric(f32, x, iptr);
|
||||
}
|
||||
|
||||
fn testModf(comptime T: type) !void {
|
||||
// Choose the appropriate `modf` impl to test based on type
|
||||
const f = switch (T) {
|
||||
f64 => modf,
|
||||
f32 => modff,
|
||||
else => @compileError("modf not implemented for " ++ @typeName(T)),
|
||||
};
|
||||
|
||||
var int: T = undefined;
|
||||
const iptr = ∫
|
||||
const eps_val: comptime_float = @max(1e-6, math.floatEps(T));
|
||||
|
||||
const normal_frac = f(@as(T, 1234.567), iptr);
|
||||
// Account for precision error
|
||||
const expected = 1234.567 - @as(T, 1234);
|
||||
try expectApproxEqAbs(expected, normal_frac, eps_val);
|
||||
try expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val);
|
||||
|
||||
// When `x` is a NaN, NaN is returned and `*iptr` is set to NaN
|
||||
const nan_frac = modf(math.nan(f64), iptr);
|
||||
const nan_frac = f(math.nan(T), iptr);
|
||||
try expect(math.isNan(nan_frac));
|
||||
try expect(math.isNan(iptr.*));
|
||||
|
||||
// When `x` is positive infinity, +0 is returned and `*iptr` is set to
|
||||
// positive infinity
|
||||
const pos_zero_frac = modf(math.inf(f64), iptr);
|
||||
const pos_zero_frac = f(math.inf(T), iptr);
|
||||
try expect(math.isPositiveZero(pos_zero_frac));
|
||||
try expect(math.isPositiveInf(iptr.*));
|
||||
|
||||
// When `x` is negative infinity, -0 is returned and `*iptr` is set to
|
||||
// negative infinity
|
||||
const neg_zero_frac = modf(-math.inf(f64), iptr);
|
||||
const neg_zero_frac = f(-math.inf(T), iptr);
|
||||
try expect(math.isNegativeZero(neg_zero_frac));
|
||||
try expect(math.isNegativeInf(iptr.*));
|
||||
|
||||
// Return -0 when `x` is a negative integer
|
||||
const nz_frac = modf(-1000.0, iptr);
|
||||
const nz_frac = f(@as(T, -1000.0), iptr);
|
||||
try expect(math.isNegativeZero(nz_frac));
|
||||
try expectEqual(-1000.0, iptr.*);
|
||||
try expectEqual(@as(T, -1000.0), iptr.*);
|
||||
|
||||
// Return +0 when `x` is a positive integer
|
||||
const pz_frac = modf(1000.0, iptr);
|
||||
const pz_frac = f(@as(T, 1000.0), iptr);
|
||||
try expect(math.isPositiveZero(pz_frac));
|
||||
try expectEqual(1000.0, iptr.*);
|
||||
try expectEqual(@as(T, 1000.0), iptr.*);
|
||||
}
|
||||
|
||||
test "modf" {
|
||||
try testModf(f64);
|
||||
try testModf(f32);
|
||||
}
|
||||
|
||||
fn nan(_: [*:0]const c_char) callconv(.c) f64 {
|
||||
|
||||
Vendored
-42
@@ -1,42 +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 <fenv.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
float
|
||||
modff (float value, float* iptr)
|
||||
{
|
||||
float int_part = 0.0F;
|
||||
/* truncate */
|
||||
/* truncate */
|
||||
#if (defined(_AMD64_) && !defined(_ARM64EC_)) || (defined(__x86_64__) && !defined(__arm64ec__))
|
||||
asm volatile ("subq $8, %%rsp\n"
|
||||
"fnstcw 4(%%rsp)\n"
|
||||
"movzwl 4(%%rsp), %%eax\n"
|
||||
"orb $12, %%ah\n"
|
||||
"movw %%ax, (%%rsp)\n"
|
||||
"fldcw (%%rsp)\n"
|
||||
"frndint\n"
|
||||
"fldcw 4(%%rsp)\n"
|
||||
"addq $8, %%rsp\n" : "=t" (int_part) : "0" (value) : "eax"); /* round */
|
||||
#elif defined(_X86_) || defined(__i386__)
|
||||
asm volatile ("push %%eax\n\tsubl $8, %%esp\n"
|
||||
"fnstcw 4(%%esp)\n"
|
||||
"movzwl 4(%%esp), %%eax\n"
|
||||
"orb $12, %%ah\n"
|
||||
"movw %%ax, (%%esp)\n"
|
||||
"fldcw (%%esp)\n"
|
||||
"frndint\n"
|
||||
"fldcw 4(%%esp)\n"
|
||||
"addl $8, %%esp\n\tpop %%eax\n" : "=t" (int_part) : "0" (value) : "eax"); /* round */
|
||||
#else
|
||||
int_part = truncf(value);
|
||||
#endif
|
||||
if (iptr)
|
||||
*iptr = int_part;
|
||||
return (isinf (value) ? 0.0F : value - int_part);
|
||||
}
|
||||
Vendored
-34
@@ -1,34 +0,0 @@
|
||||
#include "libm.h"
|
||||
|
||||
float modff(float x, float *iptr)
|
||||
{
|
||||
union {float f; uint32_t i;} u = {x};
|
||||
uint32_t mask;
|
||||
int e = (int)(u.i>>23 & 0xff) - 0x7f;
|
||||
|
||||
/* no fractional part */
|
||||
if (e >= 23) {
|
||||
*iptr = x;
|
||||
if (e == 0x80 && u.i<<9 != 0) { /* nan */
|
||||
return x;
|
||||
}
|
||||
u.i &= 0x80000000;
|
||||
return u.f;
|
||||
}
|
||||
/* no integral part */
|
||||
if (e < 0) {
|
||||
u.i &= 0x80000000;
|
||||
*iptr = u.f;
|
||||
return x;
|
||||
}
|
||||
|
||||
mask = 0x007fffff>>e;
|
||||
if ((u.i & mask) == 0) {
|
||||
*iptr = x;
|
||||
u.i &= 0x80000000;
|
||||
return u.f;
|
||||
}
|
||||
u.i &= ~mask;
|
||||
*iptr = u.f;
|
||||
return x - u.f;
|
||||
}
|
||||
@@ -977,7 +977,6 @@ const mingw32_x86_src = [_][]const u8{
|
||||
|
||||
const mingw32_x86_32_src = [_][]const u8{
|
||||
// ucrtbase
|
||||
"math" ++ path.sep_str ++ "modff.c",
|
||||
"math" ++ path.sep_str ++ "powf.c",
|
||||
"math" ++ path.sep_str ++ "sinhf.c",
|
||||
"math" ++ path.sep_str ++ "tanhf.c",
|
||||
|
||||
@@ -934,7 +934,6 @@ const src_files = [_][]const u8{
|
||||
"musl/src/math/__math_uflowf.c",
|
||||
"musl/src/math/__math_xflow.c",
|
||||
"musl/src/math/__math_xflowf.c",
|
||||
"musl/src/math/modff.c",
|
||||
"musl/src/math/modfl.c",
|
||||
"musl/src/math/nearbyint.c",
|
||||
"musl/src/math/nearbyintf.c",
|
||||
|
||||
@@ -755,7 +755,6 @@ const libc_top_half_src_files = [_][]const u8{
|
||||
"musl/src/math/__math_uflowf.c",
|
||||
"musl/src/math/__math_xflow.c",
|
||||
"musl/src/math/__math_xflowf.c",
|
||||
"musl/src/math/modff.c",
|
||||
"musl/src/math/modfl.c",
|
||||
"musl/src/math/nearbyintl.c",
|
||||
"musl/src/math/nextafter.c",
|
||||
|
||||
Reference in New Issue
Block a user