Module Name: src Committed By: martin Date: Sun Oct 13 15:09:58 UTC 2024
Modified Files: src/distrib/sets/lists/debug [netbsd-9]: mi src/distrib/sets/lists/tests [netbsd-9]: mi src/lib/libm/src [netbsd-9]: s_nexttoward.c src/tests/lib/libm [netbsd-9]: Makefile Added Files: src/tests/lib/libm [netbsd-9]: t_next.c Log Message: Pull up following revision(s) (requested by riastradh in ticket #963): tests/lib/libm/Makefile: revision 1.49 distrib/sets/lists/tests/mi: revision 1.1315 tests/lib/libm/t_next.c: revision 1.1 tests/lib/libm/t_next.c: revision 1.2 distrib/sets/lists/debug/mi: revision 1.435 tests/lib/libm/t_next.c: revision 1.3 tests/lib/libm/t_next.c: revision 1.4 tests/lib/libm/t_next.c: revision 1.5 tests/lib/libm/t_next.c: revision 1.6 lib/libm/src/s_nexttoward.c: revision 1.3 (all via patch) tests/lib/libm: Test nextafter/nexttoward and variants. The tests are fairly trivial but should work without any conditionals about floating-point formats. tests/lib/libm/t_next: Disable this test on VAX. But leave a replacement xfail test that fails unconditionally, to leave a reminder in the tests of PR 57881: vax libm is missing various symbols. tests/lib/libm/t_next: Fix stub on VAX. Tested building the wrong tree, oops. tests/lib/libm/t_next: Expand substantially. This covers many more potential problem areas -- and includes a new xfail test for PR lib/58236: nexttoward(3) is broken on subnormals. tests/lib/libm/t_next: nexttoward works if it's just nextafter. It's broken on platforms where long double and double aren't the same and nexttoward isn't an alias for nextafter. nexttoward(3): Fix high-word test on small positive subnormals. By this point in the logic, x can't be zero, so it's either positive or negative. The high word hx, however, can be zero, when x is a small positive subnormal. This means x is a small positive subnormal, so if x > y we are computing nextDown, and if x < y we are computing nextUp. hx is a (signed 32-bit) integer, not a double floating-point number, so it's a little silly to compare hx > 0.0. But that on its own isn't enough to trigger the bug because all signed 32-bit integers can be represented by double on all NetBSD architectures. PR lib/58236 To generate a diff of this commit: cvs rdiff -u -r1.285.2.9 -r1.285.2.10 src/distrib/sets/lists/debug/mi cvs rdiff -u -r1.818.2.7 -r1.818.2.8 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.2 -r1.2.28.1 src/lib/libm/src/s_nexttoward.c cvs rdiff -u -r1.46 -r1.46.2.1 src/tests/lib/libm/Makefile cvs rdiff -u -r0 -r1.7.6.2 src/tests/lib/libm/t_next.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/debug/mi diff -u src/distrib/sets/lists/debug/mi:1.285.2.9 src/distrib/sets/lists/debug/mi:1.285.2.10 --- src/distrib/sets/lists/debug/mi:1.285.2.9 Fri Aug 23 18:32:36 2024 +++ src/distrib/sets/lists/debug/mi Sun Oct 13 15:09:57 2024 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.285.2.9 2024/08/23 18:32:36 martin Exp $ +# $NetBSD: mi,v 1.285.2.10 2024/10/13 15:09:57 martin Exp $ ./etc/mtree/set.debug comp-sys-root ./usr/lib comp-sys-usr compatdir ./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile @@ -2230,6 +2230,7 @@ ./usr/libdata/debug/usr/tests/lib/libm/t_libm.debug tests-obsolete obsolete,compattestfile ./usr/libdata/debug/usr/tests/lib/libm/t_log.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libm/t_modf.debug tests-lib-debug debug,atf,compattestfile +./usr/libdata/debug/usr/tests/lib/libm/t_next.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libm/t_pow.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libm/t_precision.debug tests-lib-debug debug,atf,compattestfile ./usr/libdata/debug/usr/tests/lib/libm/t_round.debug tests-lib-debug debug,atf,compattestfile Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.818.2.7 src/distrib/sets/lists/tests/mi:1.818.2.8 --- src/distrib/sets/lists/tests/mi:1.818.2.7 Fri Aug 23 18:32:36 2024 +++ src/distrib/sets/lists/tests/mi Sun Oct 13 15:09:57 2024 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.818.2.7 2024/08/23 18:32:36 martin Exp $ +# $NetBSD: mi,v 1.818.2.8 2024/10/13 15:09:57 martin Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -3187,6 +3187,7 @@ ./usr/tests/lib/libm/t_libm tests-obsolete obsolete ./usr/tests/lib/libm/t_log tests-lib-tests compattestfile,atf ./usr/tests/lib/libm/t_modf tests-lib-tests compattestfile,atf +./usr/tests/lib/libm/t_next tests-lib-tests compattestfile,atf ./usr/tests/lib/libm/t_pow tests-lib-tests compattestfile,atf ./usr/tests/lib/libm/t_precision tests-lib-tests compattestfile,atf ./usr/tests/lib/libm/t_round tests-lib-tests compattestfile,atf Index: src/lib/libm/src/s_nexttoward.c diff -u src/lib/libm/src/s_nexttoward.c:1.2 src/lib/libm/src/s_nexttoward.c:1.2.28.1 --- src/lib/libm/src/s_nexttoward.c:1.2 Wed Aug 21 13:03:56 2013 +++ src/lib/libm/src/s_nexttoward.c Sun Oct 13 15:09:57 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: s_nexttoward.c,v 1.2 2013/08/21 13:03:56 martin Exp $ */ +/* $NetBSD: s_nexttoward.c,v 1.2.28.1 2024/10/13 15:09:57 martin Exp $ */ /* @(#)s_nextafter.c 5.1 93/09/24 */ /* @@ -13,7 +13,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: s_nexttoward.c,v 1.2 2013/08/21 13:03:56 martin Exp $"); +__RCSID("$NetBSD: s_nexttoward.c,v 1.2.28.1 2024/10/13 15:09:57 martin Exp $"); /* * We assume that a long double has a 15-bit exponent. On systems @@ -71,7 +71,7 @@ nexttoward(double x, long double y) return x; /* raise underflow flag */ } - if ((hx > 0.0) ^ (x < y)) { /* x -= ulp */ + if ((hx >= 0) ^ (x < y)) { /* x -= ulp */ if (lx == 0) hx -= 1; lx -= 1; } else { /* x += ulp */ Index: src/tests/lib/libm/Makefile diff -u src/tests/lib/libm/Makefile:1.46 src/tests/lib/libm/Makefile:1.46.2.1 --- src/tests/lib/libm/Makefile:1.46 Fri Apr 26 08:52:16 2019 +++ src/tests/lib/libm/Makefile Sun Oct 13 15:09:57 2024 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.46 2019/04/26 08:52:16 maya Exp $ +# $NetBSD: Makefile,v 1.46.2.1 2024/10/13 15:09:57 martin Exp $ .include <bsd.own.mk> @@ -35,6 +35,7 @@ TESTS_C+= t_infinity TESTS_C+= t_ldexp TESTS_C+= t_log TESTS_C+= t_modf +TESTS_C+= t_next TESTS_C+= t_pow TESTS_C+= t_precision TESTS_C+= t_round Added files: Index: src/tests/lib/libm/t_next.c diff -u /dev/null src/tests/lib/libm/t_next.c:1.7.6.2 --- /dev/null Sun Oct 13 15:09:58 2024 +++ src/tests/lib/libm/t_next.c Sun Oct 13 15:09:57 2024 @@ -0,0 +1,885 @@ +/* $NetBSD: t_next.c,v 1.7.6.2 2024/10/13 15:09:57 martin Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_next.c,v 1.7.6.2 2024/10/13 15:09:57 martin Exp $"); + +#include <atf-c.h> +#include <float.h> +#include <math.h> + +#ifdef __vax__ /* XXX PR 57881: vax libm is missing various symbols */ + +ATF_TC(vaxafter); +ATF_TC_HEAD(vaxafter, tc) +{ + + atf_tc_set_md_var(tc, "descr", "vax nextafter/nexttoward reminder"); +} +ATF_TC_BODY(vaxafter, tc) +{ + + atf_tc_expect_fail("PR 57881: vax libm is missing various symbols"); + atf_tc_fail("missing nextafter{,f,l} and nexttoward{,f,l} on vax"); +} + +#else /* !__vax__ */ + +#define CHECK(i, next, x, d, y) do \ +{ \ + volatile __typeof__(x) check_x = (x); \ + volatile __typeof__(d) check_d = (d); \ + volatile __typeof__(y) check_y = (y); \ + const volatile __typeof__(y) check_tmp = (next)(check_x, check_d); \ + ATF_CHECK_MSG(check_tmp == check_y, \ + "[%u] %s(%s=%La=%Lg, %s=%La=%Lg)=%La=%Lg != %s=%La=%Lg", \ + (i), #next, \ + #x, (long double)check_x, (long double)check_x, \ + #d, (long double)check_d, (long double)check_d, \ + (long double)check_tmp, (long double)check_tmp, \ + #y, (long double)check_y, (long double)check_y); \ +} while (0) + +/* + * check(x, n) + * + * x[0], x[1], ..., x[n - 1] are consecutive double floating-point + * numbers. Verify nextafter and nexttoward follow exactly this + * sequence, forward and back, and in negative. + */ +static void +check(const double *x, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + CHECK(i, nextafter, x[i], x[i], x[i]); + CHECK(i, nexttoward, x[i], x[i], x[i]); + CHECK(i, nextafter, -x[i], -x[i], -x[i]); + CHECK(i, nexttoward, -x[i], -x[i], -x[i]); + } + + for (i = 0; i < n - 1; i++) { + ATF_REQUIRE_MSG(x[i] < x[i + 1], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttoward, x[i], x[i]*(1 + LDBL_EPSILON), + x[i + 1]); + } + + CHECK(i, nextafter, x[i], x[i + 1], x[i + 1]); + CHECK(i, nexttoward, x[i], x[i + 1], x[i + 1]); + CHECK(i, nextafter, x[i], x[n - 1], x[i + 1]); + CHECK(i, nexttoward, x[i], x[n - 1], x[i + 1]); + CHECK(i, nextafter, x[i], INFINITY, x[i + 1]); + CHECK(i, nexttoward, x[i], INFINITY, x[i + 1]); + + CHECK(i, nextafter, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nexttoward, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nextafter, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nexttoward, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nextafter, -x[i], -INFINITY, -x[i + 1]); + CHECK(i, nexttoward, -x[i], -INFINITY, -x[i + 1]); + } + + for (i = n; i --> 1;) { + ATF_REQUIRE_MSG(x[i - 1] < x[i], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttoward, x[i], x[i]*(1 - LDBL_EPSILON/2), + x[i - 1]); + } + + CHECK(i, nextafter, x[i], x[i - 1], x[i - 1]); + CHECK(i, nexttoward, x[i], x[i - 1], x[i - 1]); + CHECK(i, nextafter, x[i], x[0], x[i - 1]); + CHECK(i, nexttoward, x[i], x[0], x[i - 1]); + CHECK(i, nextafter, x[i], +0., x[i - 1]); + CHECK(i, nexttoward, x[i], +0., x[i - 1]); + CHECK(i, nextafter, x[i], -0., x[i - 1]); + CHECK(i, nexttoward, x[i], -0., x[i - 1]); + CHECK(i, nextafter, x[i], -x[0], x[i - 1]); + CHECK(i, nexttoward, x[i], -x[0], x[i - 1]); + CHECK(i, nextafter, x[i], -x[i], x[i - 1]); + CHECK(i, nexttoward, x[i], -x[i], x[i - 1]); + CHECK(i, nextafter, x[i], -INFINITY, x[i - 1]); + CHECK(i, nexttoward, x[i], -INFINITY, x[i - 1]); + + CHECK(i, nextafter, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nexttoward, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nextafter, -x[i], -x[0], -x[i - 1]); + CHECK(i, nexttoward, -x[i], -x[0], -x[i - 1]); + CHECK(i, nextafter, -x[i], -0., -x[i - 1]); + CHECK(i, nexttoward, -x[i], -0., -x[i - 1]); + CHECK(i, nextafter, -x[i], +0., -x[i - 1]); + CHECK(i, nexttoward, -x[i], +0., -x[i - 1]); + CHECK(i, nextafter, -x[i], x[0], -x[i - 1]); + CHECK(i, nexttoward, -x[i], x[0], -x[i - 1]); + CHECK(i, nextafter, -x[i], INFINITY, -x[i - 1]); + CHECK(i, nexttoward, -x[i], INFINITY, -x[i - 1]); + } +} + +/* + * checkf(x, n) + * + * x[0], x[1], ..., x[n - 1] are consecutive single floating-point + * numbers. Verify nextafterf and nexttowardf follow exactly this + * sequence, forward and back, and in negative. + */ +static void +checkf(const float *x, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + CHECK(i, nextafterf, x[i], x[i], x[i]); + CHECK(i, nexttowardf, x[i], x[i], x[i]); + CHECK(i, nextafterf, -x[i], -x[i], -x[i]); + CHECK(i, nexttowardf, -x[i], -x[i], -x[i]); + } + + for (i = 0; i < n - 1; i++) { + ATF_REQUIRE_MSG(x[i] < x[i + 1], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttowardf, x[i], x[i]*(1 + LDBL_EPSILON), + x[i + 1]); + } + + CHECK(i, nextafterf, x[i], x[i + 1], x[i + 1]); + CHECK(i, nexttowardf, x[i], x[i + 1], x[i + 1]); + CHECK(i, nextafterf, x[i], x[n - 1], x[i + 1]); + CHECK(i, nexttowardf, x[i], x[n - 1], x[i + 1]); + CHECK(i, nextafterf, x[i], INFINITY, x[i + 1]); + CHECK(i, nexttowardf, x[i], INFINITY, x[i + 1]); + + CHECK(i, nextafterf, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nexttowardf, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nextafterf, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nexttowardf, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nextafterf, -x[i], -INFINITY, -x[i + 1]); + CHECK(i, nexttowardf, -x[i], -INFINITY, -x[i + 1]); + } + + for (i = n; i --> 1;) { + ATF_REQUIRE_MSG(x[i - 1] < x[i], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttowardf, x[i], x[i]*(1 - LDBL_EPSILON/2), + x[i - 1]); + } + + CHECK(i, nextafterf, x[i], x[i - 1], x[i - 1]); + CHECK(i, nexttowardf, x[i], x[i - 1], x[i - 1]); + CHECK(i, nextafterf, x[i], x[0], x[i - 1]); + CHECK(i, nexttowardf, x[i], x[0], x[i - 1]); + CHECK(i, nextafterf, x[i], +0., x[i - 1]); + CHECK(i, nexttowardf, x[i], +0., x[i - 1]); + CHECK(i, nextafterf, x[i], -0., x[i - 1]); + CHECK(i, nexttowardf, x[i], -0., x[i - 1]); + CHECK(i, nextafterf, x[i], -x[0], x[i - 1]); + CHECK(i, nexttowardf, x[i], -x[0], x[i - 1]); + CHECK(i, nextafterf, x[i], -x[i], x[i - 1]); + CHECK(i, nexttowardf, x[i], -x[i], x[i - 1]); + CHECK(i, nextafterf, x[i], -INFINITY, x[i - 1]); + CHECK(i, nexttowardf, x[i], -INFINITY, x[i - 1]); + + CHECK(i, nextafterf, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nexttowardf, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nextafterf, -x[i], -x[0], -x[i - 1]); + CHECK(i, nexttowardf, -x[i], -x[0], -x[i - 1]); + CHECK(i, nextafterf, -x[i], -0., -x[i - 1]); + CHECK(i, nexttowardf, -x[i], -0., -x[i - 1]); + CHECK(i, nextafterf, -x[i], +0., -x[i - 1]); + CHECK(i, nexttowardf, -x[i], +0., -x[i - 1]); + CHECK(i, nextafterf, -x[i], x[0], -x[i - 1]); + CHECK(i, nexttowardf, -x[i], x[0], -x[i - 1]); + CHECK(i, nextafterf, -x[i], INFINITY, -x[i - 1]); + CHECK(i, nexttowardf, -x[i], INFINITY, -x[i - 1]); + } +} + +/* + * checkl(x, n) + * + * x[0], x[1], ..., x[n - 1] are consecutive long double + * floating-point numbers. Verify nextafterl and nexttowardl + * follow exactly this sequence, forward and back, and in + * negative. + */ +static void +checkl(const long double *x, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + CHECK(i, nextafterl, x[i], x[i], x[i]); + CHECK(i, nexttowardl, x[i], x[i], x[i]); + CHECK(i, nextafterl, -x[i], -x[i], -x[i]); + CHECK(i, nexttowardl, -x[i], -x[i], -x[i]); + } + + for (i = 0; i < n - 1; i++) { + ATF_REQUIRE_MSG(x[i] < x[i + 1], "i=%u", i); + + CHECK(i, nextafterl, x[i], x[i + 1], x[i + 1]); + CHECK(i, nexttowardl, x[i], x[i + 1], x[i + 1]); + CHECK(i, nextafterl, x[i], x[n - 1], x[i + 1]); + CHECK(i, nexttowardl, x[i], x[n - 1], x[i + 1]); + CHECK(i, nextafterl, x[i], INFINITY, x[i + 1]); + CHECK(i, nexttowardl, x[i], INFINITY, x[i + 1]); + + CHECK(i, nextafterl, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nexttowardl, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nextafterl, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nexttowardl, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nextafterl, -x[i], -INFINITY, -x[i + 1]); + CHECK(i, nexttowardl, -x[i], -INFINITY, -x[i + 1]); + } + + for (i = n; i --> 1;) { + ATF_REQUIRE_MSG(x[i - 1] < x[i], "i=%u", i); + + CHECK(i, nextafterl, x[i], x[i - 1], x[i - 1]); + CHECK(i, nexttowardl, x[i], x[i - 1], x[i - 1]); + CHECK(i, nextafterl, x[i], x[0], x[i - 1]); + CHECK(i, nexttowardl, x[i], x[0], x[i - 1]); + CHECK(i, nextafterl, x[i], +0., x[i - 1]); + CHECK(i, nexttowardl, x[i], +0., x[i - 1]); + CHECK(i, nextafterl, x[i], -0., x[i - 1]); + CHECK(i, nexttowardl, x[i], -0., x[i - 1]); + CHECK(i, nextafterl, x[i], -x[0], x[i - 1]); + CHECK(i, nexttowardl, x[i], -x[0], x[i - 1]); + CHECK(i, nextafterl, x[i], -x[i], x[i - 1]); + CHECK(i, nexttowardl, x[i], -x[i], x[i - 1]); + CHECK(i, nextafterl, x[i], -INFINITY, x[i - 1]); + CHECK(i, nexttowardl, x[i], -INFINITY, x[i - 1]); + + CHECK(i, nextafterl, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nexttowardl, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nextafterl, -x[i], -x[0], -x[i - 1]); + CHECK(i, nexttowardl, -x[i], -x[0], -x[i - 1]); + CHECK(i, nextafterl, -x[i], -0., -x[i - 1]); + CHECK(i, nexttowardl, -x[i], -0., -x[i - 1]); + CHECK(i, nextafterl, -x[i], +0., -x[i - 1]); + CHECK(i, nexttowardl, -x[i], +0., -x[i - 1]); + CHECK(i, nextafterl, -x[i], x[0], -x[i - 1]); + CHECK(i, nexttowardl, -x[i], x[0], -x[i - 1]); + CHECK(i, nextafterl, -x[i], INFINITY, -x[i - 1]); + CHECK(i, nexttowardl, -x[i], INFINITY, -x[i - 1]); + } +} + +ATF_TC(next_nan); +ATF_TC_HEAD(next_nan, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward on NaN"); +} +ATF_TC_BODY(next_nan, tc) +{ +#ifdef NAN + /* XXX verify the NaN is quiet */ + ATF_CHECK(isnan(nextafter(NAN, 0))); + ATF_CHECK(isnan(nexttoward(NAN, 0))); + ATF_CHECK(isnan(nextafter(0, NAN))); + ATF_CHECK(isnan(nexttoward(0, NAN))); +#else + atf_tc_skip("no NaNs on this architecture"); +#endif +} + +ATF_TC(next_signed_0); +ATF_TC_HEAD(next_signed_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward on signed 0"); +} +ATF_TC_BODY(next_signed_0, tc) +{ + volatile double z_pos = +0.; + volatile double z_neg = -0.; +#ifdef __DBL_HAS_DENORM__ + volatile double m = __DBL_DENORM_MIN__; +#else + volatile double m = DBL_MIN; +#endif + + if (signbit(z_pos) == signbit(z_neg)) + atf_tc_skip("no signed zeroes on this architecture"); + + /* + * `nextUp(x) is the least floating-point number in the format + * of x that compares greater than x. [...] nextDown(x) is + * -nextUp(-x).' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafter and nexttoward, which implement the + * nextUp and nextDown operations, obey this rule and don't + * send -0 to +0 or +0 to -0, respectively. + */ + + CHECK(0, nextafter, z_neg, +INFINITY, m); + CHECK(1, nexttoward, z_neg, +INFINITY, m); + CHECK(2, nextafter, z_pos, +INFINITY, m); + CHECK(3, nexttoward, z_pos, +INFINITY, m); + + CHECK(4, nextafter, z_pos, -INFINITY, -m); + CHECK(5, nexttoward, z_pos, -INFINITY, -m); + CHECK(6, nextafter, z_neg, -INFINITY, -m); + CHECK(7, nexttoward, z_neg, -INFINITY, -m); + + /* + * `If x is the negative number of least magnitude in x's + * format, nextUp(x) is -0.' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafter and nexttoward return the correctly + * signed zero. + */ + CHECK(8, nextafter, -m, +INFINITY, 0); + CHECK(9, nexttoward, -m, +INFINITY, 0); + ATF_CHECK(signbit(nextafter(-m, +INFINITY)) != 0); + CHECK(10, nextafter, m, -INFINITY, 0); + CHECK(11, nexttoward, m, -INFINITY, 0); + ATF_CHECK(signbit(nextafter(m, -INFINITY)) == 0); +} + +ATF_TC(next_near_0); +ATF_TC_HEAD(next_near_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near 0"); +} +ATF_TC_BODY(next_near_0, tc) +{ + static const double x[] = { + [0] = 0, +#ifdef __DBL_HAS_DENORM__ + [1] = __DBL_DENORM_MIN__, + [2] = 2*__DBL_DENORM_MIN__, + [3] = 3*__DBL_DENORM_MIN__, + [4] = 4*__DBL_DENORM_MIN__, +#else + [1] = DBL_MIN, + [2] = DBL_MIN*(1 + DBL_EPSILON), + [3] = DBL_MIN*(1 + 2*DBL_EPSILON), + [4] = DBL_MIN*(1 + 3*DBL_EPSILON), +#endif + }; + + check(x, __arraycount(x)); +} + +ATF_TC(next_near_sub_normal); +ATF_TC_HEAD(next_near_sub_normal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "nextafter/nexttoward near the subnormal/normal boundary"); +} +ATF_TC_BODY(next_near_sub_normal, tc) +{ +#ifdef __DBL_HAS_DENORM__ + static const double x[] = { + [0] = DBL_MIN - 3*__DBL_DENORM_MIN__, + [1] = DBL_MIN - 2*__DBL_DENORM_MIN__, + [2] = DBL_MIN - __DBL_DENORM_MIN__, + [3] = DBL_MIN, + [4] = DBL_MIN + __DBL_DENORM_MIN__, + [5] = DBL_MIN + 2*__DBL_DENORM_MIN__, + [6] = DBL_MIN + 3*__DBL_DENORM_MIN__, + }; + + check(x, __arraycount(x)); +#else /* !__DBL_HAS_DENORM__ */ + atf_tc_skip("no subnormals on this architecture"); +#endif /* !__DBL_HAS_DENORM__ */ +} + +ATF_TC(next_near_1); +ATF_TC_HEAD(next_near_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near 1"); +} +ATF_TC_BODY(next_near_1, tc) +{ + static const double x[] = { + [0] = 1 - 3*DBL_EPSILON/2, + [1] = 1 - 2*DBL_EPSILON/2, + [2] = 1 - DBL_EPSILON/2, + [3] = 1, + [4] = 1 + DBL_EPSILON, + [5] = 1 + 2*DBL_EPSILON, + [6] = 1 + 3*DBL_EPSILON, + }; + + check(x, __arraycount(x)); +} + +ATF_TC(next_near_1_5); +ATF_TC_HEAD(next_near_1_5, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near 1.5"); +} +ATF_TC_BODY(next_near_1_5, tc) +{ + static const double x[] = { + [0] = 1.5 - 3*DBL_EPSILON, + [1] = 1.5 - 2*DBL_EPSILON, + [2] = 1.5 - DBL_EPSILON, + [3] = 1.5, + [4] = 1.5 + DBL_EPSILON, + [5] = 1.5 + 2*DBL_EPSILON, + [6] = 1.5 + 3*DBL_EPSILON, + }; + + check(x, __arraycount(x)); +} + +ATF_TC(next_near_infinity); +ATF_TC_HEAD(next_near_infinity, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near infinity"); +} +ATF_TC_BODY(next_near_infinity, tc) +{ + static const double x[] = { + [0] = DBL_MAX, + [1] = INFINITY, + }; + volatile double t; + + if (!isinf(INFINITY)) + atf_tc_skip("no infinities on this architecture"); + + check(x, __arraycount(x)); + + ATF_CHECK_EQ_MSG((t = nextafter(INFINITY, INFINITY)), INFINITY, + "t=%a=%g", t, t); + ATF_CHECK_EQ_MSG((t = nextafter(-INFINITY, -INFINITY)), -INFINITY, + "t=%a=%g", t, t); +} + +ATF_TC(nextf_nan); +ATF_TC_HEAD(nextf_nan, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf on NaN"); +} +ATF_TC_BODY(nextf_nan, tc) +{ +#ifdef NAN + /* XXX verify the NaN is quiet */ + ATF_CHECK(isnan(nextafterf(NAN, 0))); + ATF_CHECK(isnan(nexttowardf(NAN, 0))); + ATF_CHECK(isnan(nextafterf(0, NAN))); + ATF_CHECK(isnan(nexttowardf(0, NAN))); +#else + atf_tc_skip("no NaNs on this architecture"); +#endif +} + +ATF_TC(nextf_signed_0); +ATF_TC_HEAD(nextf_signed_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf on signed 0"); +} +ATF_TC_BODY(nextf_signed_0, tc) +{ + volatile float z_pos = +0.; + volatile float z_neg = -0.; +#ifdef __FLT_HAS_DENORM__ + volatile float m = __FLT_DENORM_MIN__; +#else + volatile float m = FLT_MIN; +#endif + + if (signbit(z_pos) == signbit(z_neg)) + atf_tc_skip("no signed zeroes on this architecture"); + + /* + * `nextUp(x) is the least floating-point number in the format + * of x that compares greater than x. [...] nextDown(x) is + * -nextUp(-x).' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafterf and nexttowardf, which implement the + * nextUp and nextDown operations, obey this rule and don't + * send -0 to +0 or +0 to -0, respectively. + */ + + CHECK(0, nextafterf, z_neg, +INFINITY, m); + CHECK(1, nexttowardf, z_neg, +INFINITY, m); + CHECK(2, nextafterf, z_pos, +INFINITY, m); + CHECK(3, nexttowardf, z_pos, +INFINITY, m); + + CHECK(4, nextafterf, z_pos, -INFINITY, -m); + CHECK(5, nexttowardf, z_pos, -INFINITY, -m); + CHECK(6, nextafterf, z_neg, -INFINITY, -m); + CHECK(7, nexttowardf, z_neg, -INFINITY, -m); + + /* + * `If x is the negative number of least magnitude in x's + * format, nextUp(x) is -0.' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + */ + CHECK(8, nextafterf, -m, +INFINITY, 0); + CHECK(9, nexttowardf, -m, +INFINITY, 0); + ATF_CHECK(signbit(nextafterf(-m, +INFINITY)) != 0); + CHECK(10, nextafterf, m, -INFINITY, 0); + CHECK(11, nexttowardf, m, -INFINITY, 0); + ATF_CHECK(signbit(nextafterf(m, -INFINITY)) == 0); +} + +ATF_TC(nextf_near_0); +ATF_TC_HEAD(nextf_near_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near 0"); +} +ATF_TC_BODY(nextf_near_0, tc) +{ + static const float x[] = { + [0] = 0, +#ifdef __FLT_HAS_DENORM__ + [1] = __FLT_DENORM_MIN__, + [2] = 2*__FLT_DENORM_MIN__, + [3] = 3*__FLT_DENORM_MIN__, + [4] = 4*__FLT_DENORM_MIN__, +#else + [1] = FLT_MIN, + [2] = FLT_MIN*(1 + FLT_EPSILON), + [3] = FLT_MIN*(1 + 2*FLT_EPSILON), + [4] = FLT_MIN*(1 + 3*FLT_EPSILON), +#endif + }; + + checkf(x, __arraycount(x)); +} + +ATF_TC(nextf_near_sub_normal); +ATF_TC_HEAD(nextf_near_sub_normal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "nextafterf/nexttowardf near the subnormal/normal boundary"); +} +ATF_TC_BODY(nextf_near_sub_normal, tc) +{ +#ifdef __FLT_HAS_DENORM__ + static const float x[] = { + [0] = FLT_MIN - 3*__FLT_DENORM_MIN__, + [1] = FLT_MIN - 2*__FLT_DENORM_MIN__, + [2] = FLT_MIN - __FLT_DENORM_MIN__, + [3] = FLT_MIN, + [4] = FLT_MIN + __FLT_DENORM_MIN__, + [5] = FLT_MIN + 2*__FLT_DENORM_MIN__, + [6] = FLT_MIN + 3*__FLT_DENORM_MIN__, + }; + + checkf(x, __arraycount(x)); +#else /* !__FLT_HAS_DENORM__ */ + atf_tc_skip("no subnormals on this architecture"); +#endif /* !__FLT_HAS_DENORM__ */ +} + +ATF_TC(nextf_near_1); +ATF_TC_HEAD(nextf_near_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near 1"); +} +ATF_TC_BODY(nextf_near_1, tc) +{ + static const float x[] = { + [0] = 1 - 3*FLT_EPSILON/2, + [1] = 1 - 2*FLT_EPSILON/2, + [2] = 1 - FLT_EPSILON/2, + [3] = 1, + [4] = 1 + FLT_EPSILON, + [5] = 1 + 2*FLT_EPSILON, + [6] = 1 + 3*FLT_EPSILON, + }; + + checkf(x, __arraycount(x)); +} + +ATF_TC(nextf_near_1_5); +ATF_TC_HEAD(nextf_near_1_5, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near 1.5"); +} +ATF_TC_BODY(nextf_near_1_5, tc) +{ + static const float x[] = { + [0] = 1.5 - 3*FLT_EPSILON, + [1] = 1.5 - 2*FLT_EPSILON, + [2] = 1.5 - FLT_EPSILON, + [3] = 1.5, + [4] = 1.5 + FLT_EPSILON, + [5] = 1.5 + 2*FLT_EPSILON, + [6] = 1.5 + 3*FLT_EPSILON, + }; + + checkf(x, __arraycount(x)); +} + +ATF_TC(nextf_near_infinity); +ATF_TC_HEAD(nextf_near_infinity, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near infinity"); +} +ATF_TC_BODY(nextf_near_infinity, tc) +{ + static const float x[] = { + [0] = FLT_MAX, + [1] = INFINITY, + }; + volatile float t; + + if (!isinf(INFINITY)) + atf_tc_skip("no infinities on this architecture"); + + checkf(x, __arraycount(x)); + + ATF_CHECK_EQ_MSG((t = nextafterf(INFINITY, INFINITY)), INFINITY, + "t=%a=%g", t, t); + ATF_CHECK_EQ_MSG((t = nextafterf(-INFINITY, -INFINITY)), -INFINITY, + "t=%a=%g", t, t); +} + +ATF_TC(nextl_nan); +ATF_TC_HEAD(nextl_nan, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl on NaN"); +} +ATF_TC_BODY(nextl_nan, tc) +{ +#ifdef NAN + /* XXX verify the NaN is quiet */ + ATF_CHECK(isnan(nextafterl(NAN, 0))); + ATF_CHECK(isnan(nexttowardl(NAN, 0))); + ATF_CHECK(isnan(nextafterl(0, NAN))); + ATF_CHECK(isnan(nexttowardl(0, NAN))); +#else + atf_tc_skip("no NaNs on this architecture"); +#endif +} + +ATF_TC(nextl_signed_0); +ATF_TC_HEAD(nextl_signed_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl on signed 0"); +} +ATF_TC_BODY(nextl_signed_0, tc) +{ + volatile long double z_pos = +0.; + volatile long double z_neg = -0.; +#ifdef __LDBL_HAS_DENORM__ + volatile long double m = __LDBL_DENORM_MIN__; +#else + volatile long double m = LDBL_MIN; +#endif + + if (signbit(z_pos) == signbit(z_neg)) + atf_tc_skip("no signed zeroes on this architecture"); + + /* + * `nextUp(x) is the least floating-point number in the format + * of x that compares greater than x. [...] nextDown(x) is + * -nextUp(-x).' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafterl and nexttowardl, which implement the + * nextUp and nextDown operations, obey this rule and don't + * send -0 to +0 or +0 to -0, respectively. + */ + + CHECK(0, nextafterl, z_neg, +INFINITY, m); + CHECK(1, nexttowardl, z_neg, +INFINITY, m); + CHECK(2, nextafterl, z_pos, +INFINITY, m); + CHECK(3, nexttowardl, z_pos, +INFINITY, m); + + CHECK(4, nextafterl, z_pos, -INFINITY, -m); + CHECK(5, nexttowardl, z_pos, -INFINITY, -m); + CHECK(6, nextafterl, z_neg, -INFINITY, -m); + CHECK(7, nexttowardl, z_neg, -INFINITY, -m); + + /* + * `If x is the negative number of least magnitude in x's + * format, nextUp(x) is -0.' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + */ + CHECK(8, nextafterl, -m, +INFINITY, 0); + CHECK(9, nexttowardl, -m, +INFINITY, 0); + ATF_CHECK(signbit(nextafterl(-m, +INFINITY)) != 0); + CHECK(10, nextafterl, m, -INFINITY, 0); + CHECK(11, nexttowardl, m, -INFINITY, 0); + ATF_CHECK(signbit(nextafterl(m, -INFINITY)) == 0); +} + +ATF_TC(nextl_near_0); +ATF_TC_HEAD(nextl_near_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near 0"); +} +ATF_TC_BODY(nextl_near_0, tc) +{ + static const long double x[] = { + [0] = 0, +#ifdef __LDBL_HAS_DENORM__ + [1] = __LDBL_DENORM_MIN__, + [2] = 2*__LDBL_DENORM_MIN__, + [3] = 3*__LDBL_DENORM_MIN__, + [4] = 4*__LDBL_DENORM_MIN__, +#else + [1] = LDBL_MIN, + [2] = LDBL_MIN*(1 + LDBL_EPSILON), + [3] = LDBL_MIN*(1 + 2*LDBL_EPSILON), + [4] = LDBL_MIN*(1 + 3*LDBL_EPSILON), +#endif + }; + + checkl(x, __arraycount(x)); +} + +ATF_TC(nextl_near_sub_normal); +ATF_TC_HEAD(nextl_near_sub_normal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "nextafterl/nexttowardl near the subnormal/normal boundary"); +} +ATF_TC_BODY(nextl_near_sub_normal, tc) +{ +#ifdef __LDBL_HAS_DENORM__ + static const long double x[] = { + [0] = LDBL_MIN - 3*__LDBL_DENORM_MIN__, + [1] = LDBL_MIN - 2*__LDBL_DENORM_MIN__, + [2] = LDBL_MIN - __LDBL_DENORM_MIN__, + [3] = LDBL_MIN, + [4] = LDBL_MIN + __LDBL_DENORM_MIN__, + [5] = LDBL_MIN + 2*__LDBL_DENORM_MIN__, + [6] = LDBL_MIN + 3*__LDBL_DENORM_MIN__, + }; + + checkl(x, __arraycount(x)); +#else /* !__LDBL_HAS_DENORM__ */ + atf_tc_skip("no subnormals on this architecture"); +#endif /* !__LDBL_HAS_DENORM__ */ +} + +ATF_TC(nextl_near_1); +ATF_TC_HEAD(nextl_near_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near 1"); +} +ATF_TC_BODY(nextl_near_1, tc) +{ + static const long double x[] = { + [0] = 1 - 3*LDBL_EPSILON/2, + [1] = 1 - 2*LDBL_EPSILON/2, + [2] = 1 - LDBL_EPSILON/2, + [3] = 1, + [4] = 1 + LDBL_EPSILON, + [5] = 1 + 2*LDBL_EPSILON, + [6] = 1 + 3*LDBL_EPSILON, + }; + + checkl(x, __arraycount(x)); +} + +ATF_TC(nextl_near_1_5); +ATF_TC_HEAD(nextl_near_1_5, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near 1.5"); +} +ATF_TC_BODY(nextl_near_1_5, tc) +{ + static const long double x[] = { + [0] = 1.5 - 3*LDBL_EPSILON, + [1] = 1.5 - 2*LDBL_EPSILON, + [2] = 1.5 - LDBL_EPSILON, + [3] = 1.5, + [4] = 1.5 + LDBL_EPSILON, + [5] = 1.5 + 2*LDBL_EPSILON, + [6] = 1.5 + 3*LDBL_EPSILON, + }; + + checkl(x, __arraycount(x)); +} + +ATF_TC(nextl_near_infinity); +ATF_TC_HEAD(nextl_near_infinity, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near infinity"); +} +ATF_TC_BODY(nextl_near_infinity, tc) +{ + static const long double x[] = { + [0] = LDBL_MAX, + [1] = INFINITY, + }; + volatile long double t; + + if (!isinf(INFINITY)) + atf_tc_skip("no infinities on this architecture"); + + checkl(x, __arraycount(x)); + + ATF_CHECK_EQ_MSG((t = nextafterl(INFINITY, INFINITY)), INFINITY, + "t=%La=%Lg", t, t); + ATF_CHECK_EQ_MSG((t = nextafterl(-INFINITY, -INFINITY)), -INFINITY, + "t=%La=%Lg", t, t); +} + +#endif /* __vax__ */ + +ATF_TP_ADD_TCS(tp) +{ + +#ifdef __vax__ + ATF_TP_ADD_TC(tp, vaxafter); +#else + ATF_TP_ADD_TC(tp, next_nan); + ATF_TP_ADD_TC(tp, next_near_0); + ATF_TP_ADD_TC(tp, next_near_1); + ATF_TP_ADD_TC(tp, next_near_1_5); + ATF_TP_ADD_TC(tp, next_near_infinity); + ATF_TP_ADD_TC(tp, next_near_sub_normal); + ATF_TP_ADD_TC(tp, next_signed_0); + ATF_TP_ADD_TC(tp, nextf_nan); + ATF_TP_ADD_TC(tp, nextf_near_0); + ATF_TP_ADD_TC(tp, nextf_near_1); + ATF_TP_ADD_TC(tp, nextf_near_1_5); + ATF_TP_ADD_TC(tp, nextf_near_infinity); + ATF_TP_ADD_TC(tp, nextf_near_sub_normal); + ATF_TP_ADD_TC(tp, nextf_signed_0); + ATF_TP_ADD_TC(tp, nextl_nan); + ATF_TP_ADD_TC(tp, nextl_near_0); + ATF_TP_ADD_TC(tp, nextl_near_1); + ATF_TP_ADD_TC(tp, nextl_near_1_5); + ATF_TP_ADD_TC(tp, nextl_near_infinity); + ATF_TP_ADD_TC(tp, nextl_near_sub_normal); + ATF_TP_ADD_TC(tp, nextl_signed_0); +#endif + return atf_no_error(); +}