Module Name: src Committed By: riastradh Date: Sat May 11 19:08:30 UTC 2024
Modified Files: src/tests/lib/libm: t_hypot.c Log Message: tests/lib/libm/t_hypot: Expand substantially. PR lib/58245: hypotl is broken on ld128 ports To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/tests/lib/libm/t_hypot.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/lib/libm/t_hypot.c diff -u src/tests/lib/libm/t_hypot.c:1.2 src/tests/lib/libm/t_hypot.c:1.3 --- src/tests/lib/libm/t_hypot.c:1.2 Thu Jun 25 11:12:03 2020 +++ src/tests/lib/libm/t_hypot.c Sat May 11 19:08:29 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: t_hypot.c,v 1.2 2020/06/25 11:12:03 jruoho Exp $ */ +/* $NetBSD: t_hypot.c,v 1.3 2024/05/11 19:08:29 riastradh Exp $ */ /*- * Copyright (c) 2016 The NetBSD Foundation, Inc. @@ -27,33 +27,486 @@ */ #include <atf-c.h> +#include <float.h> #include <math.h> -ATF_TC(hypot_integer); -ATF_TC_HEAD(hypot_integer, tc) +#define CHECK_EQ(i, hypot, a, b, c) \ + ATF_CHECK_MSG(hypot(a, b) == (c), \ + "[%u] %s(%a, %a)=%a, expected %a", \ + (i), #hypot, (a), (b), hypot(a, b), (c)) + +#define CHECKL_EQ(i, hypot, a, b, c) \ + ATF_CHECK_MSG(hypot(a, b) == (c), \ + "[%u] %s(%La, %La)=%La, expected %La", \ + (i), #hypot, (a), (b), hypot(a, b), (c)) + +static const float trivial_casesf[] = { + 0, +#ifdef __FLT_HAS_DENORM__ + __FLT_DENORM_MIN__, + 2*__FLT_DENORM_MIN__, + 3*__FLT_DENORM_MIN__, + FLT_MIN - 3*__FLT_DENORM_MIN__, + FLT_MIN - 2*__FLT_DENORM_MIN__, + FLT_MIN - __FLT_DENORM_MIN__, +#endif + FLT_MIN, + FLT_MIN*(1 + FLT_EPSILON), + FLT_MIN*(1 + 2*FLT_EPSILON), + 2*FLT_MIN, + FLT_EPSILON/2, + FLT_EPSILON, + 2*FLT_EPSILON, + 1 - 3*FLT_EPSILON/2, + 1 - 2*FLT_EPSILON/2, + 1 - FLT_EPSILON/2, + 1, + 1 + FLT_EPSILON, + 1 + 2*FLT_EPSILON, + 1 + 3*FLT_EPSILON, + 1.5 - 3*FLT_EPSILON, + 1.5 - 2*FLT_EPSILON, + 1.5 - FLT_EPSILON, + 1.5, + 1.5 + FLT_EPSILON, + 1.5 + 2*FLT_EPSILON, + 1.5 + 3*FLT_EPSILON, + 2, + 0.5/FLT_EPSILON - 0.5, + 0.5/FLT_EPSILON, + 0.5/FLT_EPSILON + 0.5, + 1/FLT_EPSILON, + FLT_MAX, + INFINITY, +}; + +static const double trivial_cases[] = { + 0, +#ifdef __DBL_HAS_DENORM__ + __DBL_DENORM_MIN__, + 2*__DBL_DENORM_MIN__, + 3*__DBL_DENORM_MIN__, + DBL_MIN - 3*__DBL_DENORM_MIN__, + DBL_MIN - 2*__DBL_DENORM_MIN__, + DBL_MIN - __DBL_DENORM_MIN__, +#endif + DBL_MIN, + DBL_MIN*(1 + DBL_EPSILON), + DBL_MIN*(1 + 2*DBL_EPSILON), + 2*DBL_MIN, + DBL_EPSILON/2, + DBL_EPSILON, + 2*DBL_EPSILON, + 1 - 3*DBL_EPSILON/2, + 1 - 2*DBL_EPSILON/2, + 1 - DBL_EPSILON/2, + 1, + 1 + DBL_EPSILON, + 1 + 2*DBL_EPSILON, + 1 + 3*DBL_EPSILON, + 1.5 - 3*DBL_EPSILON, + 1.5 - 2*DBL_EPSILON, + 1.5 - DBL_EPSILON, + 1.5, + 1.5 + DBL_EPSILON, + 1.5 + 2*DBL_EPSILON, + 1.5 + 3*DBL_EPSILON, + 2, + 1/FLT_EPSILON - 0.5, + 1/FLT_EPSILON, + 1/FLT_EPSILON + 0.5, + 0.5/DBL_EPSILON - 0.5, + 0.5/DBL_EPSILON, + 0.5/DBL_EPSILON + 0.5, + 1/DBL_EPSILON, + DBL_MAX, + INFINITY, +}; + +static const long double trivial_casesl[] = { + 0, +#ifdef __LDBL_HAS_DENORM__ + __LDBL_DENORM_MIN__, + 2*__LDBL_DENORM_MIN__, + 3*__LDBL_DENORM_MIN__, + LDBL_MIN - 3*__LDBL_DENORM_MIN__, + LDBL_MIN - 2*__LDBL_DENORM_MIN__, + LDBL_MIN - __LDBL_DENORM_MIN__, +#endif + LDBL_MIN, + LDBL_MIN*(1 + LDBL_EPSILON), + LDBL_MIN*(1 + 2*LDBL_EPSILON), + 2*LDBL_MIN, + LDBL_EPSILON/2, + LDBL_EPSILON, + 2*LDBL_EPSILON, + 1 - 3*LDBL_EPSILON/2, + 1 - 2*LDBL_EPSILON/2, + 1 - LDBL_EPSILON/2, + 1, + 1 + LDBL_EPSILON, + 1 + 2*LDBL_EPSILON, + 1 + 3*LDBL_EPSILON, + 1.5 - 3*LDBL_EPSILON, + 1.5 - 2*LDBL_EPSILON, + 1.5 - LDBL_EPSILON, + 1.5, + 1.5 + LDBL_EPSILON, + 1.5 + 2*LDBL_EPSILON, + 1.5 + 3*LDBL_EPSILON, + 2, + 1/FLT_EPSILON - 0.5, + 1/FLT_EPSILON, + 1/FLT_EPSILON + 0.5, +#ifdef __HAVE_LONG_DOUBLE + 1/DBL_EPSILON - 0.5L, + 1/DBL_EPSILON, + 1/DBL_EPSILON + 0.5L, +#endif + 0.5/LDBL_EPSILON - 0.5, + 0.5/LDBL_EPSILON, + 0.5/LDBL_EPSILON + 0.5, + 1/LDBL_EPSILON, + LDBL_MAX, + INFINITY, +}; + +ATF_TC(hypotf_trivial); +ATF_TC_HEAD(hypotf_trivial, tc) +{ + atf_tc_set_md_var(tc, "descr", "hypotf(x,0) and hypotf(0,x)"); +} +ATF_TC_BODY(hypotf_trivial, tc) +{ + unsigned i; + + for (i = 0; i < __arraycount(trivial_casesf); i++) { + volatile float y, x = trivial_casesf[i]; + + ATF_CHECK_EQ_MSG((y = hypotf(x, 0)), x, + "[%u] x=%g=%a hypotf(x, 0)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotf(-x, 0)), x, + "[%u] x=%g=%a hypotf(-x, 0)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotf(0, x)), x, + "[%u] x=%g=%a hypotf(0, x)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotf(0, -x)), x, + "[%u] x=%g=%a hypotf(0, -x)=x=%g=%a", + i, x, x, y, y); + } +} + +ATF_TC(hypot_trivial); +ATF_TC_HEAD(hypot_trivial, tc) +{ + atf_tc_set_md_var(tc, "descr", "hypot(x,0) and hypot(0,x)"); +} +ATF_TC_BODY(hypot_trivial, tc) +{ + unsigned i; + + for (i = 0; i < __arraycount(trivial_casesf); i++) { + volatile double y, x = trivial_casesf[i]; + + ATF_CHECK_EQ_MSG((y = hypot(x, 0)), x, + "[%u] x=%g=%a hypot(x, 0)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypot(-x, 0)), x, + "[%u] x=%g=%a hypot(-x, 0)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypot(0, x)), x, + "[%u] x=%g=%a hypot(0, x)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypot(0, -x)), x, + "[%u] x=%g=%a hypot(0, -x)=x=%g=%a", + i, x, x, y, y); + } + + for (i = 0; i < __arraycount(trivial_cases); i++) { + volatile double y, x = trivial_cases[i]; + + ATF_CHECK_EQ_MSG((y = hypot(x, 0)), x, + "[%u] x=%g=%a hypot(x, 0)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypot(-x, 0)), x, + "[%u] x=%g=%a hypot(-x, 0)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypot(0, x)), x, + "[%u] x=%g=%a hypot(0, x)=x=%g=%a", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypot(0, -x)), x, + "[%u] x=%g=%a hypot(0, -x)=x=%g=%a", + i, x, x, y, y); + } +} + +ATF_TC(hypotl_trivial); +ATF_TC_HEAD(hypotl_trivial, tc) +{ + atf_tc_set_md_var(tc, "descr", "hypotl(x,0) and hypotl(0,x)"); +} +ATF_TC_BODY(hypotl_trivial, tc) { - atf_tc_set_md_var(tc, "descr", "Test hypot with integer args"); + unsigned i; + + for (i = 0; i < __arraycount(trivial_casesf); i++) { + volatile long double y, x = trivial_casesf[i]; + + ATF_CHECK_EQ_MSG((y = hypotl(x, 0)), x, + "[%u] x=%Lg=%La hypotl(x, 0)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(-x, 0)), x, + "[%u] x=%Lg=%La hypotl(-x, 0)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(0, x)), x, + "[%u] x=%Lg=%La hypotl(0, x)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(0, -x)), x, + "[%u] x=%Lg=%La hypotl(0, -x)=x=%Lg=%La", + i, x, x, y, y); + } + + for (i = 0; i < __arraycount(trivial_cases); i++) { + volatile long double y, x = trivial_cases[i]; + + ATF_CHECK_EQ_MSG((y = hypotl(x, 0)), x, + "[%u] x=%Lg=%La hypotl(x, 0)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(-x, 0)), x, + "[%u] x=%Lg=%La hypotl(-x, 0)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(0, x)), x, + "[%u] x=%Lg=%La hypotl(0, x)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(0, -x)), x, + "[%u] x=%Lg=%La hypotl(0, -x)=x=%Lg=%La", + i, x, x, y, y); + } + +#if __HAVE_LONG_DOUBLE + 0 == 128 + atf_tc_expect_fail("PR lib/58245: hypotl is broken on ld128 ports"); +#endif + + for (i = 0; i < __arraycount(trivial_casesl); i++) { + volatile long double y, x = trivial_casesl[i]; + + ATF_CHECK_EQ_MSG((y = hypotl(x, 0)), x, + "[%u] x=%Lg=%La hypotl(x, 0)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(-x, 0)), x, + "[%u] x=%Lg=%La hypotl(-x, 0)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(0, x)), x, + "[%u] x=%Lg=%La hypotl(0, x)=x=%Lg=%La", + i, x, x, y, y); + ATF_CHECK_EQ_MSG((y = hypotl(0, -x)), x, + "[%u] x=%Lg=%La hypotl(0, -x)=x=%Lg=%La", + i, x, x, y, y); + } } -ATF_TC_BODY(hypot_integer, tc) +__CTASSERT(FLT_MANT_DIG >= 24); +static const struct { + float a, b, c; +} exact_casesf[] = { + { 3, 4, 5 }, + { 5, 12, 13 }, + { 9, 12, 15 }, + { 0x1001, 0x801000, 0x801001 }, + { 4248257, 1130976, 4396225 }, +}; + +__CTASSERT(DBL_MANT_DIG >= 53); +static const struct { + double a, b, c; +} exact_cases[] = { + { 3378249543467007, 4505248894795776, 5631148868747265 }, + { 0x7ffffff, 0x1ffffff8000000, 0x1ffffff8000001 }, +#if DBL_MANT_DIG >= 56 + { 13514123525517439, 18018830919909120, 22523538851237761 }, + { 0x1fffffff, 0x1ffffffe0000000, 0x1ffffffe0000001 }, +#endif +}; + +#if LDBL_MANT_DIG >= 64 +static const struct { + long double a, b, c; +} exact_casesl[] = { + { 3458976450080784639, 4611968592949214720, 5764960744407842561 }, + { 0x1ffffffff, 0x1fffffffe00000000p0L, 0x1fffffffe00000001p0L }, +#if LDBL_MANT_DIG >= 113 + { 973555668229277869436257492279295.L, + 1298074224305703705819019479072768.L, + 1622592780382129686316970078625793.L }, + { 0x1ffffffffffffff, + 0x1fffffffffffffe00000000000000p0L, + 0x1fffffffffffffe00000000000001p0L }, +#endif +}; +#endif + +ATF_TC(hypotf_exact); +ATF_TC_HEAD(hypotf_exact, tc) { - /* volatile so hypotf() won't be evaluated at compile time */ - volatile double a = 5; - volatile double b = 12; - ATF_CHECK(hypot(a, b) == 13.0); + atf_tc_set_md_var(tc, "descr", "hypotf on scaled Pythagorean triples"); +} +ATF_TC_BODY(hypotf_exact, tc) +{ + unsigned i; + + for (i = 0; i < __arraycount(exact_casesf); i++) { + int s; + + for (s = FLT_MIN_EXP; + s < FLT_MAX_EXP - FLT_MANT_DIG; + s += (FLT_MAX_EXP - FLT_MANT_DIG - FLT_MIN_EXP)/5) { + volatile double a = ldexpf(exact_casesf[i].a, s); + volatile double b = ldexpf(exact_casesf[i].b, s); + float c = ldexpf(exact_casesf[i].c, s); + + CHECK_EQ(i, hypot, a, b, c); + CHECK_EQ(i, hypot, b, a, c); + CHECK_EQ(i, hypot, a, -b, c); + CHECK_EQ(i, hypot, b, -a, c); + CHECK_EQ(i, hypot, -a, b, c); + CHECK_EQ(i, hypot, -b, a, c); + CHECK_EQ(i, hypot, -a, -b, c); + CHECK_EQ(i, hypot, -b, -a, c); + } + } } -ATF_TC(hypotf_integer); -ATF_TC_HEAD(hypotf_integer, tc) +ATF_TC(hypot_exact); +ATF_TC_HEAD(hypot_exact, tc) { - atf_tc_set_md_var(tc, "descr", "Test hypotf with integer args"); + atf_tc_set_md_var(tc, "descr", "hypot on scaled Pythagorean triples"); +} +ATF_TC_BODY(hypot_exact, tc) +{ + unsigned i; + + for (i = 0; i < __arraycount(exact_casesf); i++) { + int s; + + for (s = DBL_MIN_EXP; + s < DBL_MAX_EXP - DBL_MANT_DIG; + s += (DBL_MAX_EXP - DBL_MANT_DIG - DBL_MIN_EXP)/5) { + volatile double a = ldexp(exact_casesf[i].a, s); + volatile double b = ldexp(exact_casesf[i].b, s); + double c = ldexp(exact_casesf[i].c, s); + + CHECK_EQ(i, hypot, a, b, c); + CHECK_EQ(i, hypot, b, a, c); + CHECK_EQ(i, hypot, a, -b, c); + CHECK_EQ(i, hypot, b, -a, c); + CHECK_EQ(i, hypot, -a, b, c); + CHECK_EQ(i, hypot, -b, a, c); + CHECK_EQ(i, hypot, -a, -b, c); + CHECK_EQ(i, hypot, -b, -a, c); + } + } + + for (i = 0; i < __arraycount(exact_cases); i++) { + int s; + + for (s = DBL_MIN_EXP; + s < DBL_MAX_EXP - DBL_MANT_DIG; + s += (DBL_MAX_EXP - DBL_MANT_DIG - DBL_MIN_EXP)/5) { + volatile double a = ldexp(exact_cases[i].a, s); + volatile double b = ldexp(exact_cases[i].b, s); + double c = ldexp(exact_cases[i].c, s); + + CHECK_EQ(i, hypot, a, b, c); + CHECK_EQ(i, hypot, b, a, c); + CHECK_EQ(i, hypot, a, -b, c); + CHECK_EQ(i, hypot, b, -a, c); + CHECK_EQ(i, hypot, -a, b, c); + CHECK_EQ(i, hypot, -b, a, c); + CHECK_EQ(i, hypot, -a, -b, c); + CHECK_EQ(i, hypot, -b, -a, c); + } + } } -ATF_TC_BODY(hypotf_integer, tc) +ATF_TC(hypotl_exact); +ATF_TC_HEAD(hypotl_exact, tc) { - volatile float a = 5; - volatile float b = 12; - ATF_CHECK(hypotf(a, b) == 13.0f); + atf_tc_set_md_var(tc, "descr", "hypotl on scaled Pythagorean triples"); +} +ATF_TC_BODY(hypotl_exact, tc) +{ + unsigned i; + + for (i = 0; i < __arraycount(exact_casesf); i++) { + int s; + + for (s = LDBL_MIN_EXP; + s < LDBL_MAX_EXP - LDBL_MANT_DIG; + s += (LDBL_MAX_EXP - LDBL_MANT_DIG - LDBL_MIN_EXP)/5) { + volatile long double a = ldexpl(exact_casesf[i].a, s); + volatile long double b = ldexpl(exact_casesf[i].b, s); + long double c = ldexpl(exact_casesf[i].c, s); + + CHECKL_EQ(i, hypotl, a, b, c); + CHECKL_EQ(i, hypotl, b, a, c); + CHECKL_EQ(i, hypotl, a, -b, c); + CHECKL_EQ(i, hypotl, b, -a, c); + CHECKL_EQ(i, hypotl, -a, b, c); + CHECKL_EQ(i, hypotl, -b, a, c); + CHECKL_EQ(i, hypotl, -a, -b, c); + CHECKL_EQ(i, hypotl, -b, -a, c); + } + } + + for (i = 0; i < __arraycount(exact_cases); i++) { + int s; + + for (s = LDBL_MIN_EXP; + s < LDBL_MAX_EXP - LDBL_MANT_DIG; + s += (LDBL_MAX_EXP - LDBL_MANT_DIG - LDBL_MIN_EXP)/5) { + volatile long double a = ldexpl(exact_cases[i].a, s); + volatile long double b = ldexpl(exact_cases[i].b, s); + long double c = ldexpl(exact_cases[i].c, s); + + CHECKL_EQ(i, hypotl, a, b, c); + CHECKL_EQ(i, hypotl, b, a, c); + CHECKL_EQ(i, hypotl, a, -b, c); + CHECKL_EQ(i, hypotl, b, -a, c); + CHECKL_EQ(i, hypotl, -a, b, c); + CHECKL_EQ(i, hypotl, -b, a, c); + CHECKL_EQ(i, hypotl, -a, -b, c); + CHECKL_EQ(i, hypotl, -b, -a, c); + } + } + +#if __HAVE_LONG_DOUBLE + 0 == 128 + atf_tc_expect_fail("PR lib/58245: hypotl is broken on ld128 ports"); +#endif + +#if LDBL_MANT_DIG >= 64 + for (i = 0; i < __arraycount(exact_casesl); i++) { + int s; + + for (s = LDBL_MIN_EXP; + s < LDBL_MAX_EXP - LDBL_MANT_DIG; + s += (LDBL_MAX_EXP - LDBL_MANT_DIG - LDBL_MIN_EXP)/5) { + volatile long double a = ldexpl(exact_casesl[i].a, s); + volatile long double b = ldexpl(exact_casesl[i].b, s); + long double c = ldexpl(exact_casesl[i].c, s); + + CHECKL_EQ(i, hypotl, a, b, c); + CHECKL_EQ(i, hypotl, b, a, c); + CHECKL_EQ(i, hypotl, a, -b, c); + CHECKL_EQ(i, hypotl, b, -a, c); + CHECKL_EQ(i, hypotl, -a, b, c); + CHECKL_EQ(i, hypotl, -b, a, c); + CHECKL_EQ(i, hypotl, -a, -b, c); + CHECKL_EQ(i, hypotl, -b, -a, c); + } + } +#endif } ATF_TC(pr50698); @@ -73,8 +526,12 @@ ATF_TC_BODY(pr50698, tc) ATF_TP_ADD_TCS(tp) { - ATF_TP_ADD_TC(tp, hypot_integer); - ATF_TP_ADD_TC(tp, hypotf_integer); + ATF_TP_ADD_TC(tp, hypot_exact); + ATF_TP_ADD_TC(tp, hypot_trivial); + ATF_TP_ADD_TC(tp, hypotf_exact); + ATF_TP_ADD_TC(tp, hypotf_trivial); + ATF_TP_ADD_TC(tp, hypotl_exact); + ATF_TP_ADD_TC(tp, hypotl_trivial); ATF_TP_ADD_TC(tp, pr50698); return atf_no_error();