Module Name: src
Committed By: riastradh
Date: Mon Jul 15 06:19:17 UTC 2024
Modified Files:
src/tests/lib/libm: t_log.c
Log Message:
tests/lib/libm/t_log.c: Expand to handle many more cases.
Also make this much more concise.
Prompted by PR lib/58337: logl() crashes on arm64
To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/tests/lib/libm/t_log.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_log.c
diff -u src/tests/lib/libm/t_log.c:1.15 src/tests/lib/libm/t_log.c:1.16
--- src/tests/lib/libm/t_log.c:1.15 Sun Jun 9 16:53:12 2024
+++ src/tests/lib/libm/t_log.c Mon Jul 15 06:19:17 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: t_log.c,v 1.15 2024/06/09 16:53:12 riastradh Exp $ */
+/* $NetBSD: t_log.c,v 1.16 2024/07/15 06:19:17 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,836 +29,590 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_log.c,v 1.15 2024/06/09 16:53:12 riastradh Exp $");
+__RCSID("$NetBSD: t_log.c,v 1.16 2024/07/15 06:19:17 riastradh Exp $");
#include <atf-c.h>
+#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
+#define CHECK_EQ(i, f, x, y) \
+ ATF_CHECK_EQ_MSG(f(x), y, \
+ "[%u] %s(%a=%.17g)=%a=%.17g, expected %a=%.17g", \
+ (i), #f, (double)(x), (double)(x), f(x), f(x), \
+ (double)(y), (double)(y))
+
+#define CHECKL_EQ(i, f, x, y) \
+ ATF_CHECK_EQ_MSG(f(x), y, \
+ "[%u] %s(%La=%.17Lg)=%La=%.17Lg, expected %La=%.17Lg", \
+ (i), #f, (long double)(x), (long double)(x), f(x), f(x), \
+ (long double)(y), (long double)(y))
+
+#ifdef NAN
+
+#define CHECK_NAN(i, f, x) \
+ ATF_CHECK_MSG(isnan(f(x)), \
+ "[%u] %s(%a=%.17g)=%a=%.17g, expected NaN", \
+ (i), #f, (x), (x), f(x), f(x))
+
+#define CHECKL_NAN(i, f, x) \
+ ATF_CHECK_MSG(isnan(f(x)), \
+ "[%u] %s(%La=%.17Lg)=%La=%.17Lg, expected NaN", \
+ (i), #f, (long double)(x), (long double)(x), f(x), f(x))
+
+#else /* !defined(NAN) */
+
+#define CHECK_NAN(i, f, x) do \
+{ \
+ int _checknan_error; \
+ double _checknan_result; \
+ errno = 0; \
+ _checknan_result = f(x); \
+ _checknan_error = errno; \
+ ATF_CHECK_EQ_MSG(errno, EDOM, \
+ "[%u] %s(%a=%.17g)=%a=%.17g errno=%d, expected EDOM=%d", \
+ (i), #f, (double)(x), (double)(x), \
+ _checknan_result, _checknan_result, \
+ _checknan_error, EDOM); \
+} while (0)
+
+#define CHECKL_NAN(i, f, x) do \
+{ \
+ int _checknan_error; \
+ long double _checknan_result; \
+ errno = 0; \
+ _checknan_result = f(x); \
+ _checknan_error = errno; \
+ ATF_CHECK_EQ_MSG(errno, EDOM, \
+ "[%u] %s(%La=%.17Lg)=%La=%.17Lg errno=%d, expected EDOM=%d", \
+ (i), #f, (long double)(x), (long double)(x), \
+ _checknan_result, _checknan_result, \
+ _checknan_error, EDOM); \
+} while (0)
+
+#endif /* NAN */
+
+static const float logf_invalid[] = {
+#ifdef NAN
+ NAN,
+#endif
+ -HUGE_VALF,
+ -FLT_MAX,
+ -10,
+ -1,
+ -FLT_EPSILON,
+ -FLT_MIN,
+#ifdef FLT_DENORM_MIN
+ -FLT_DENORM_MIN,
+#endif
+};
+
+static const double log_invalid[] = {
+#ifdef NAN
+ NAN,
+#endif
+ -HUGE_VAL,
+ -DBL_MAX,
+ -10,
+ -1,
+ -DBL_EPSILON,
+ -DBL_MIN,
+#ifdef DBL_DENORM_MIN
+ -DBL_DENORM_MIN,
+#endif
+};
+
+static const long double logl_invalid[] = {
+#ifdef NAN
+ NAN,
+#endif
+ -HUGE_VALL,
+ -LDBL_MAX,
+ -10,
+ -1,
+ -LDBL_EPSILON,
+ -LDBL_MIN,
+#ifdef LDBL_DENORM_MIN
+ -LDBL_DENORM_MIN,
+#endif
+};
+
+static const float log1pf_invalid[] = {
+#ifdef NAN
+ NAN,
+#endif
+ -HUGE_VALF,
+ -FLT_MAX,
+ -10,
+ -1 - FLT_EPSILON,
+};
+
+static const double log1p_invalid[] = {
+#ifdef NAN
+ NAN,
+#endif
+ -HUGE_VAL,
+ -DBL_MAX,
+ -10,
+ -1 - DBL_EPSILON,
+};
+
+static const long double log1pl_invalid[] = {
+#ifdef NAN
+ NAN,
+#endif
+ -HUGE_VALL,
+ -LDBL_MAX,
+ -10,
+ -1 - LDBL_EPSILON,
+};
+
/*
* log10(3)
*/
-ATF_TC(log10_base);
-ATF_TC_HEAD(log10_base, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(10) == 1");
-}
-
-ATF_TC_BODY(log10_base, tc)
-{
- ATF_CHECK(log10(10.0) == 1.0);
-}
-
-ATF_TC(log10_nan);
-ATF_TC_HEAD(log10_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(NaN) == NaN");
-}
-
-ATF_TC_BODY(log10_nan, tc)
-{
- const double x = 0.0L / 0.0L;
-
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log10(x)) != 0);
-}
-
-ATF_TC(log10_inf_neg);
-ATF_TC_HEAD(log10_inf_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(-Inf) == NaN");
-}
-
-ATF_TC_BODY(log10_inf_neg, tc)
-{
- const double x = -1.0L / 0.0L;
- const double y = log10(x);
-
- ATF_CHECK(isnan(y) != 0);
-}
-
-ATF_TC(log10_inf_pos);
-ATF_TC_HEAD(log10_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(+Inf) == +Inf");
-}
-
-ATF_TC_BODY(log10_inf_pos, tc)
-{
- const double x = 1.0L / 0.0L;
-
- ATF_CHECK(log10(x) == x);
-}
-
-ATF_TC(log10_one_pos);
-ATF_TC_HEAD(log10_one_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(1.0) == +0.0");
-}
-
-ATF_TC_BODY(log10_one_pos, tc)
-{
- const double x = log10(1.0);
- const double y = 0.0L;
-
- ATF_CHECK(x == y);
- ATF_CHECK(signbit(x) == 0);
- ATF_CHECK(signbit(y) == 0);
-}
-
-ATF_TC(log10_zero_neg);
-ATF_TC_HEAD(log10_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(-0.0) == -HUGE_VAL");
-}
-
-ATF_TC_BODY(log10_zero_neg, tc)
-{
- const double x = -0.0L;
-
- ATF_CHECK(log10(x) == -HUGE_VAL);
-}
-
-ATF_TC(log10_zero_pos);
-ATF_TC_HEAD(log10_zero_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10(+0.0) == -HUGE_VAL");
-}
-
-ATF_TC_BODY(log10_zero_pos, tc)
-{
- const double x = 0.0L;
-
- ATF_CHECK(log10(x) == -HUGE_VAL);
-}
+static const struct {
+ float x, y;
+} log10f_exact[] = {
+ { 1, 0 },
+ { 10, 1 },
+ { 100, 2 },
+};
-/*
- * log10f(3)
- */
-ATF_TC(log10f_base);
-ATF_TC_HEAD(log10f_base, tc)
+ATF_TC(log10_invalid);
+ATF_TC_HEAD(log10_invalid, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log10f(10) == 1");
+ atf_tc_set_md_var(tc, "descr", "Test log10/f/l on invalid inputs");
}
-
-ATF_TC_BODY(log10f_base, tc)
+ATF_TC_BODY(log10_invalid, tc)
{
- ATF_CHECK(log10f(10.0) == 1.0);
-}
+ unsigned i;
-ATF_TC(log10f_nan);
-ATF_TC_HEAD(log10f_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10f(NaN) == NaN");
-}
+ for (i = 0; i < __arraycount(logf_invalid); i++) {
+ CHECK_NAN(i, log10f, logf_invalid[i]);
+ CHECK_NAN(i, log10, logf_invalid[i]);
+ CHECKL_NAN(i, log10l, logf_invalid[i]);
+ }
-ATF_TC_BODY(log10f_nan, tc)
-{
- const float x = 0.0L / 0.0L;
+ for (i = 0; i < __arraycount(log_invalid); i++) {
+ CHECK_NAN(i, log10, log_invalid[i]);
+ CHECKL_NAN(i, log10l, log_invalid[i]);
+ }
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log10f(x)) != 0);
+ for (i = 0; i < __arraycount(logl_invalid); i++) {
+ CHECKL_NAN(i, log10l, logl_invalid[i]);
+ }
}
-ATF_TC(log10f_inf_neg);
-ATF_TC_HEAD(log10f_inf_neg, tc)
+ATF_TC(log10_zero);
+ATF_TC_HEAD(log10_zero, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log10f(-Inf) == NaN");
+ atf_tc_set_md_var(tc, "descr", "Test log10/f/l on zero");
}
-
-ATF_TC_BODY(log10f_inf_neg, tc)
+ATF_TC_BODY(log10_zero, tc)
{
- const float x = -1.0L / 0.0L;
- const float y = log10f(x);
- ATF_CHECK(isnan(y) != 0);
-}
+ CHECK_EQ(0, log10f, +0., -HUGE_VALF);
+ CHECK_EQ(0, log10, +0., -HUGE_VAL);
+ CHECKL_EQ(0, log10l, +0., -HUGE_VALL);
-ATF_TC(log10f_inf_pos);
-ATF_TC_HEAD(log10f_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10f(+Inf) == +Inf");
+ CHECK_EQ(1, log10f, -0., -HUGE_VALF);
+ CHECK_EQ(1, log10, -0., -HUGE_VAL);
+ CHECKL_EQ(1, log10l, -0., -HUGE_VALL);
}
-ATF_TC_BODY(log10f_inf_pos, tc)
+ATF_TC(log10_exact);
+ATF_TC_HEAD(log10_exact, tc)
{
- const float x = 1.0L / 0.0L;
-
- ATF_CHECK(log10f(x) == x);
+ atf_tc_set_md_var(tc, "descr", "Test log10/f/l exact cases");
}
-
-ATF_TC(log10f_one_pos);
-ATF_TC_HEAD(log10f_one_pos, tc)
+ATF_TC_BODY(log10_exact, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log10f(1.0) == +0.0");
-}
+ unsigned i;
-ATF_TC_BODY(log10f_one_pos, tc)
-{
- const float x = log10f(1.0);
- const float y = 0.0L;
+ ATF_CHECK_EQ(signbit(log10f(1)), 0);
+ ATF_CHECK_EQ(signbit(log10(1)), 0);
+ ATF_CHECK_EQ(signbit(log10l(1)), 0);
- ATF_CHECK(x == y);
- ATF_CHECK(signbit(x) == 0);
- ATF_CHECK(signbit(y) == 0);
-}
+ for (i = 0; i < __arraycount(log10f_exact); i++) {
+ const float x = log10f_exact[i].x;
+ const float y = log10f_exact[i].y;
-ATF_TC(log10f_zero_neg);
-ATF_TC_HEAD(log10f_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log10f(-0.0) == -HUGE_VALF");
+ CHECK_EQ(i, log10f, x, y);
+ CHECK_EQ(i, log10, x, y);
+ CHECKL_EQ(i, log10l, x, y);
+ }
}
-ATF_TC_BODY(log10f_zero_neg, tc)
+ATF_TC(log10_inf);
+ATF_TC_HEAD(log10_inf, tc)
{
- const float x = -0.0L;
-
- ATF_CHECK(log10f(x) == -HUGE_VALF);
+ atf_tc_set_md_var(tc, "descr", "Test log10/f/l on +infinity");
}
-
-ATF_TC(log10f_zero_pos);
-ATF_TC_HEAD(log10f_zero_pos, tc)
+ATF_TC_BODY(log10_inf, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log10f(+0.0) == -HUGE_VALF");
-}
-ATF_TC_BODY(log10f_zero_pos, tc)
-{
- const float x = 0.0L;
+ if (!isinf(INFINITY))
+ atf_tc_skip("no infinities on this architecture");
- ATF_CHECK(log10f(x) == -HUGE_VALF);
+ CHECK_EQ(0, log10f, INFINITY, INFINITY);
+ CHECK_EQ(0, log10, INFINITY, INFINITY);
+ CHECKL_EQ(0, log10l, INFINITY, INFINITY);
}
/*
* log1p(3)
*/
-ATF_TC(log1p_nan);
-ATF_TC_HEAD(log1p_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1p(NaN) == NaN");
-}
-
-ATF_TC_BODY(log1p_nan, tc)
-{
- const double x = 0.0L / 0.0L;
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log1p(x)) != 0);
-}
-
-ATF_TC(log1p_inf_neg);
-ATF_TC_HEAD(log1p_inf_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1p(-Inf) == NaN");
-}
-
-ATF_TC_BODY(log1p_inf_neg, tc)
-{
- const volatile double x = -1.0 / 0.0;
- const double y = log1p(x);
-
- ATF_CHECK_MSG(isnan(y), "y=%a", y);
-}
-
-ATF_TC(log1p_inf_pos);
-ATF_TC_HEAD(log1p_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1p(+Inf) == +Inf");
-}
-
-ATF_TC_BODY(log1p_inf_pos, tc)
-{
- const double x = 1.0L / 0.0L;
-
- ATF_CHECK(log1p(x) == x);
-}
-
-ATF_TC(log1p_one_neg);
-ATF_TC_HEAD(log1p_one_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1p(-1.0) == -HUGE_VAL");
-}
-
-ATF_TC_BODY(log1p_one_neg, tc)
-{
- const volatile double x = -1.0;
- const double y = log1p(x);
-
- ATF_CHECK_EQ_MSG(y, -HUGE_VAL, "y=%a", y);
-}
-
-ATF_TC(log1p_zero_neg);
-ATF_TC_HEAD(log1p_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1p(-0.0) == -0.0");
-}
-
-ATF_TC_BODY(log1p_zero_neg, tc)
-{
- const double x = -0.0L;
-
- ATF_CHECK(log1p(x) == x);
-}
-
-ATF_TC(log1p_zero_pos);
-ATF_TC_HEAD(log1p_zero_pos, tc)
+ATF_TC(log1p_invalid);
+ATF_TC_HEAD(log1p_invalid, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log1p(+0.0) == +0.0");
+ atf_tc_set_md_var(tc, "descr", "Test log1p/f/l on invalid inputs");
}
-
-ATF_TC_BODY(log1p_zero_pos, tc)
+ATF_TC_BODY(log1p_invalid, tc)
{
- const double x = 0.0L;
+ unsigned i;
- ATF_CHECK(log1p(x) == x);
-}
-
-/*
- * log1pf(3)
- */
-ATF_TC(log1pf_nan);
-ATF_TC_HEAD(log1pf_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1pf(NaN) == NaN");
-}
+ for (i = 0; i < __arraycount(log1pf_invalid); i++) {
+ CHECK_NAN(i, log1pf, log1pf_invalid[i]);
+ CHECK_NAN(i, log1p, log1pf_invalid[i]);
+ CHECKL_NAN(i, log1pl, log1pf_invalid[i]);
+ }
-ATF_TC_BODY(log1pf_nan, tc)
-{
- const float x = 0.0L / 0.0L;
+ for (i = 0; i < __arraycount(log1p_invalid); i++) {
+ CHECK_NAN(i, log1p, log1p_invalid[i]);
+ CHECKL_NAN(i, log1pl, log1p_invalid[i]);
+ }
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log1pf(x)) != 0);
+ for (i = 0; i < __arraycount(log1pl_invalid); i++) {
+ CHECKL_NAN(i, log1pl, log1pl_invalid[i]);
+ }
}
-ATF_TC(log1pf_inf_neg);
-ATF_TC_HEAD(log1pf_inf_neg, tc)
+ATF_TC(log1p_neg_one);
+ATF_TC_HEAD(log1p_neg_one, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log1pf(-Inf) == NaN");
+ atf_tc_set_md_var(tc, "descr", "Test log1p/f/l on -1");
}
-
-ATF_TC_BODY(log1pf_inf_neg, tc)
+ATF_TC_BODY(log1p_neg_one, tc)
{
- const volatile float x = -1.0f / 0.0f;
- const float y = log1pf(x);
- ATF_CHECK_MSG(isnan(y), "y=%a", y);
+ CHECK_EQ(0, log1pf, -1., -HUGE_VALF);
+ CHECK_EQ(0, log1p, -1., -HUGE_VAL);
+ CHECKL_EQ(0, log1pl, -1., -HUGE_VALL);
}
-ATF_TC(log1pf_inf_pos);
-ATF_TC_HEAD(log1pf_inf_pos, tc)
+ATF_TC(log1p_exact);
+ATF_TC_HEAD(log1p_exact, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log1pf(+Inf) == +Inf");
+ atf_tc_set_md_var(tc, "descr", "Test log1p/f/l exact cases");
}
-
-ATF_TC_BODY(log1pf_inf_pos, tc)
+ATF_TC_BODY(log1p_exact, tc)
{
- const float x = 1.0L / 0.0L;
- ATF_CHECK(log1pf(x) == x);
-}
+ /*
+ * Not _exact_, but the approximation is good enough.
+ */
+#ifdef FLT_DENORM_MIN
+ CHECK_EQ(0, log1pf, -FLT_DENORM_MIN, -FLT_DENORM_MIN);
+#endif
+#ifdef DBL_DENORM_MIN
+ CHECK_EQ(0, log1p, -DBL_DENORM_MIN, -DBL_DENORM_MIN);
+#endif
+#ifdef LDBL_DENORM_MIN
+ CHECKL_EQ(0, log1pl, -LDBL_DENORM_MIN, -LDBL_DENORM_MIN);
+#endif
-ATF_TC(log1pf_one_neg);
-ATF_TC_HEAD(log1pf_one_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1pf(-1.0) == -HUGE_VALF");
-}
+ CHECK_EQ(1, log1pf, -FLT_MIN, -FLT_MIN);
+ CHECK_EQ(1, log1p, -DBL_MIN, -DBL_MIN);
+ CHECKL_EQ(1, log1pl, -LDBL_MIN, -LDBL_MIN);
-ATF_TC_BODY(log1pf_one_neg, tc)
-{
- const volatile float x = -1.0f;
- const float y = log1pf(x);
+ CHECK_EQ(0, log1pf, -0., 0);
+ CHECK_EQ(0, log1p, -0., 0);
+ CHECKL_EQ(0, log1pl, -0., 0);
- ATF_CHECK_EQ_MSG(y, -HUGE_VALF, "y=%a", y);
-}
+ CHECK_EQ(1, log1pf, +0., 0);
+ CHECK_EQ(1, log1p, +0., 0);
+ CHECKL_EQ(1, log1pl, +0., 0);
-ATF_TC(log1pf_zero_neg);
-ATF_TC_HEAD(log1pf_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log1pf(-0.0) == -0.0");
+ CHECK_EQ(2, log1pf, 1, logf(2));
+ CHECK_EQ(2, log1p, 1, log(2));
+ CHECKL_EQ(2, log1pl, 1, logl(2));
}
-ATF_TC_BODY(log1pf_zero_neg, tc)
+ATF_TC(log1p_inf);
+ATF_TC_HEAD(log1p_inf, tc)
{
- const float x = -0.0L;
-
- ATF_CHECK(log1pf(x) == x);
+ atf_tc_set_md_var(tc, "descr", "Test log1p/f/l on +infinity");
}
-
-ATF_TC(log1pf_zero_pos);
-ATF_TC_HEAD(log1pf_zero_pos, tc)
+ATF_TC_BODY(log1p_inf, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log1pf(+0.0) == +0.0");
-}
-ATF_TC_BODY(log1pf_zero_pos, tc)
-{
- const float x = 0.0L;
+ if (!isinf(INFINITY))
+ atf_tc_skip("no infinities on this architecture");
- ATF_CHECK(log1pf(x) == x);
+ CHECK_EQ(0, log1pf, INFINITY, INFINITY);
+ CHECK_EQ(0, log1p, INFINITY, INFINITY);
+ CHECKL_EQ(0, log1pl, INFINITY, INFINITY);
}
/*
* log2(3)
*/
-ATF_TC(log2_base);
-ATF_TC_HEAD(log2_base, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(2) == 1");
-}
-
-ATF_TC_BODY(log2_base, tc)
-{
- ATF_CHECK(log2(2.0) == 1.0);
-}
-
-ATF_TC(log2_nan);
-ATF_TC_HEAD(log2_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(NaN) == NaN");
-}
-
-ATF_TC_BODY(log2_nan, tc)
-{
- const double x = 0.0L / 0.0L;
-
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log2(x)) != 0);
-}
-
-ATF_TC(log2_inf_neg);
-ATF_TC_HEAD(log2_inf_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(-Inf) == NaN");
-}
-
-ATF_TC_BODY(log2_inf_neg, tc)
-{
- const double x = -1.0L / 0.0L;
- const double y = log2(x);
-
- ATF_CHECK(isnan(y) != 0);
-}
-
-ATF_TC(log2_inf_pos);
-ATF_TC_HEAD(log2_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(+Inf) == +Inf");
-}
-
-ATF_TC_BODY(log2_inf_pos, tc)
-{
- const double x = 1.0L / 0.0L;
-
- ATF_CHECK(log2(x) == x);
-}
-
-ATF_TC(log2_one_pos);
-ATF_TC_HEAD(log2_one_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(1.0) == +0.0");
-}
-
-ATF_TC_BODY(log2_one_pos, tc)
-{
- const double x = log2(1.0);
- const double y = 0.0L;
-
- ATF_CHECK(x == y);
- ATF_CHECK(signbit(x) == 0);
- ATF_CHECK(signbit(y) == 0);
-}
-
-ATF_TC(log2_zero_neg);
-ATF_TC_HEAD(log2_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(-0.0) == -HUGE_VAL");
-}
-
-ATF_TC_BODY(log2_zero_neg, tc)
-{
- const double x = -0.0L;
-
- ATF_CHECK(log2(x) == -HUGE_VAL);
-}
-
-ATF_TC(log2_zero_pos);
-ATF_TC_HEAD(log2_zero_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2(+0.0) == -HUGE_VAL");
-}
-
-ATF_TC_BODY(log2_zero_pos, tc)
-{
- const double x = 0.0L;
-
- ATF_CHECK(log2(x) == -HUGE_VAL);
-}
-
-/*
- * log2f(3)
- */
-ATF_TC(log2f_base);
-ATF_TC_HEAD(log2f_base, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(2) == 1");
-}
-
-ATF_TC_BODY(log2f_base, tc)
-{
- ATF_CHECK(log2f(2.0) == 1.0);
-}
-
-ATF_TC(log2f_nan);
-ATF_TC_HEAD(log2f_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(NaN) == NaN");
-}
-
-ATF_TC_BODY(log2f_nan, tc)
-{
- const float x = 0.0L / 0.0L;
-
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log2f(x)) != 0);
-}
-
-ATF_TC(log2f_inf_neg);
-ATF_TC_HEAD(log2f_inf_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(-Inf) == NaN");
-}
-
-ATF_TC_BODY(log2f_inf_neg, tc)
-{
- const float x = -1.0L / 0.0L;
- const float y = log2f(x);
-
- ATF_CHECK(isnan(y) != 0);
-}
-
-ATF_TC(log2f_inf_pos);
-ATF_TC_HEAD(log2f_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(+Inf) == +Inf");
-}
-
-ATF_TC_BODY(log2f_inf_pos, tc)
-{
- const float x = 1.0L / 0.0L;
-
- ATF_CHECK(log2f(x) == x);
-}
-
-ATF_TC(log2f_one_pos);
-ATF_TC_HEAD(log2f_one_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(1.0) == +0.0");
-}
-
-ATF_TC_BODY(log2f_one_pos, tc)
-{
- const float x = log2f(1.0);
- const float y = 0.0L;
-
- ATF_CHECK(x == y);
- ATF_CHECK(signbit(x) == 0);
- ATF_CHECK(signbit(y) == 0);
-}
-
-ATF_TC(log2f_zero_neg);
-ATF_TC_HEAD(log2f_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(-0.0) == -HUGE_VALF");
-}
-
-ATF_TC_BODY(log2f_zero_neg, tc)
-{
- const float x = -0.0L;
-
- ATF_CHECK(log2f(x) == -HUGE_VALF);
-}
-
-ATF_TC(log2f_zero_pos);
-ATF_TC_HEAD(log2f_zero_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log2f(+0.0) == -HUGE_VALF");
-}
-
-ATF_TC_BODY(log2f_zero_pos, tc)
-{
- const float x = 0.0L;
-
- ATF_CHECK(log2f(x) == -HUGE_VALF);
+static const struct {
+ float x, y;
+} log2f_exact[] = {
+#ifdef FLT_DENORM_MIN
+ { FLT_DENORM_MIN, FLT_MIN_EXP - FLT_MANT_DIG },
+#endif
+ { FLT_MIN, FLT_MIN_EXP - 1 },
+ { 0.25, -2 },
+ { 0.5, -1 },
+ { 1, 0 },
+ { 2, 1 },
+ { 4, 2 },
+ { 8, 3 },
+ { 1 << FLT_MANT_DIG, FLT_MANT_DIG },
+ { (float)(1 << FLT_MANT_DIG) * (1 << FLT_MANT_DIG),
+ 2*FLT_MANT_DIG },
+};
+static const struct {
+ double x, y;
+} log2_exact[] = {
+#ifdef DBL_DENORM_MIN
+ { DBL_DENORM_MIN, DBL_MIN_EXP - DBL_MANT_DIG },
+#endif
+ { DBL_MIN, DBL_MIN_EXP - 1 },
+ { (uint64_t)1 << DBL_MANT_DIG, DBL_MANT_DIG },
+ { ((double)((uint64_t)1 << DBL_MANT_DIG) *
+ ((uint64_t)1 << DBL_MANT_DIG)),
+ 2*DBL_MANT_DIG },
+};
+
+static const struct {
+ long double x, y;
+} log2l_exact[] = {
+#ifdef LDBL_DENORM_MIN
+ { LDBL_DENORM_MIN, LDBL_MIN_EXP - LDBL_MANT_DIG },
+#endif
+ { LDBL_MIN, LDBL_MIN_EXP - 1 },
+ { ((long double)((uint64_t)1 << (LDBL_MANT_DIG/2)) *
+ ((uint64_t)1 << ((LDBL_MANT_DIG + 1)/2))),
+ LDBL_MANT_DIG },
+ { (((long double)((uint64_t)1 << (LDBL_MANT_DIG/2)) *
+ ((uint64_t)1 << ((LDBL_MANT_DIG + 1)/2))) *
+ ((long double)((uint64_t)1 << (LDBL_MANT_DIG/2)) *
+ ((uint64_t)1 << ((LDBL_MANT_DIG + 1)/2)))),
+ 2*LDBL_MANT_DIG },
+};
+
+ATF_TC(log2_invalid);
+ATF_TC_HEAD(log2_invalid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test log2/f/l on invalid inputs");
+}
+ATF_TC_BODY(log2_invalid, tc)
+{
+ unsigned i;
+
+ for (i = 0; i < __arraycount(logf_invalid); i++) {
+ CHECK_NAN(i, log2f, logf_invalid[i]);
+ CHECK_NAN(i, log2, logf_invalid[i]);
+ CHECKL_NAN(i, log2l, logf_invalid[i]);
+ }
+
+ for (i = 0; i < __arraycount(log_invalid); i++) {
+ CHECK_NAN(i, log2, log_invalid[i]);
+ CHECKL_NAN(i, log2l, log_invalid[i]);
+ }
+
+ for (i = 0; i < __arraycount(logl_invalid); i++) {
+ CHECKL_NAN(i, log2l, logl_invalid[i]);
+ }
+}
+
+ATF_TC(log2_zero);
+ATF_TC_HEAD(log2_zero, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test log2/f/l on zero");
+}
+ATF_TC_BODY(log2_zero, tc)
+{
+
+ CHECK_EQ(0, log2f, +0., -HUGE_VALF);
+ CHECK_EQ(0, log2, +0., -HUGE_VAL);
+ CHECKL_EQ(0, log2l, +0., -HUGE_VALL);
+
+ CHECK_EQ(1, log2f, -0., -HUGE_VALF);
+ CHECK_EQ(1, log2, -0., -HUGE_VAL);
+ CHECKL_EQ(1, log2l, -0., -HUGE_VALL);
+}
+
+ATF_TC(log2_exact);
+ATF_TC_HEAD(log2_exact, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test log2/f/l exact cases");
+}
+ATF_TC_BODY(log2_exact, tc)
+{
+ unsigned i;
+
+ ATF_CHECK_EQ(signbit(log2f(1)), 0);
+ ATF_CHECK_EQ(signbit(log2(1)), 0);
+ ATF_CHECK_EQ(signbit(log2l(1)), 0);
+
+ for (i = 0; i < __arraycount(log2f_exact); i++) {
+ const float x = log2f_exact[i].x;
+ const float y = log2f_exact[i].y;
+
+ CHECK_EQ(i, log2f, x, y);
+ CHECK_EQ(i, log2, x, y);
+ CHECKL_EQ(i, log2l, x, y);
+ }
+
+ for (i = 0; i < __arraycount(log2_exact); i++) {
+ const double x = log2_exact[i].x;
+ const double y = log2_exact[i].y;
+
+ CHECK_EQ(i, log2, x, y);
+ CHECKL_EQ(i, log2l, x, y);
+ }
+
+ for (i = 0; i < __arraycount(log2l_exact); i++) {
+ const long double x = log2l_exact[i].x;
+ const long double y = log2l_exact[i].y;
+
+ CHECKL_EQ(i, log2l, x, y);
+ }
+}
+
+ATF_TC(log2_inf);
+ATF_TC_HEAD(log2_inf, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test log2/f/l on +infinity");
+}
+ATF_TC_BODY(log2_inf, tc)
+{
+
+ if (!isinf(INFINITY))
+ atf_tc_skip("no infinities on this architecture");
+
+ CHECK_EQ(0, log2f, INFINITY, INFINITY);
+ CHECK_EQ(0, log2, INFINITY, INFINITY);
+ CHECKL_EQ(0, log2l, INFINITY, INFINITY);
}
/*
* log(3)
*/
-ATF_TC(log_base);
-ATF_TC_HEAD(log_base, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log(e) == 1");
-}
-
-ATF_TC_BODY(log_base, tc)
-{
- const double eps = DBL_EPSILON;
-
- if (!(fabs(log(M_E) - 1.0) <= eps))
- atf_tc_fail_nonfatal("log(e) = %.17g != 1", log(M_E));
-}
-
-ATF_TC(log_nan);
-ATF_TC_HEAD(log_nan, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log(NaN) == NaN");
-}
-ATF_TC_BODY(log_nan, tc)
+ATF_TC(log_invalid);
+ATF_TC_HEAD(log_invalid, tc)
{
- const double x = 0.0L / 0.0L;
-
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(log(x)) != 0);
+ atf_tc_set_md_var(tc, "descr", "Test log/f/l on invalid inputs");
}
-
-ATF_TC(log_inf_neg);
-ATF_TC_HEAD(log_inf_neg, tc)
+ATF_TC_BODY(log_invalid, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log(-Inf) == NaN");
-}
-
-ATF_TC_BODY(log_inf_neg, tc)
-{
- const double x = -1.0L / 0.0L;
- const double y = log(x);
-
- ATF_CHECK(isnan(y) != 0);
-}
+ unsigned i;
-ATF_TC(log_inf_pos);
-ATF_TC_HEAD(log_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log(+Inf) == +Inf");
-}
+ for (i = 0; i < __arraycount(logf_invalid); i++) {
+ CHECK_NAN(i, logf, logf_invalid[i]);
+ CHECK_NAN(i, log, logf_invalid[i]);
+ CHECKL_NAN(i, logl, logf_invalid[i]);
+ }
-ATF_TC_BODY(log_inf_pos, tc)
-{
- const double x = 1.0L / 0.0L;
+ for (i = 0; i < __arraycount(log_invalid); i++) {
+ CHECK_NAN(i, log, log_invalid[i]);
+ CHECKL_NAN(i, logl, log_invalid[i]);
+ }
- ATF_CHECK(log(x) == x);
+ for (i = 0; i < __arraycount(logl_invalid); i++) {
+ CHECKL_NAN(i, logl, logl_invalid[i]);
+ }
}
-ATF_TC(log_one_pos);
-ATF_TC_HEAD(log_one_pos, tc)
+ATF_TC(log_zero);
+ATF_TC_HEAD(log_zero, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log(1.0) == +0.0");
+ atf_tc_set_md_var(tc, "descr", "Test log/f/l on zero");
}
-
-ATF_TC_BODY(log_one_pos, tc)
+ATF_TC_BODY(log_zero, tc)
{
- const double x = log(1.0);
- const double y = 0.0L;
- ATF_CHECK(x == y);
- ATF_CHECK(signbit(x) == 0);
- ATF_CHECK(signbit(y) == 0);
-}
+ CHECK_EQ(0, logf, +0., -HUGE_VALF);
+ CHECK_EQ(0, log, +0., -HUGE_VAL);
+ CHECKL_EQ(0, logl, +0., -HUGE_VALL);
-ATF_TC(log_zero_neg);
-ATF_TC_HEAD(log_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test log(-0.0) == -HUGE_VAL");
+ CHECK_EQ(1, logf, -0., -HUGE_VALF);
+ CHECK_EQ(1, log, -0., -HUGE_VAL);
+ CHECKL_EQ(1, logl, -0., -HUGE_VALL);
}
-ATF_TC_BODY(log_zero_neg, tc)
+ATF_TC(log_normal);
+ATF_TC_HEAD(log_normal, tc)
{
- const double x = -0.0L;
-
- ATF_CHECK(log(x) == -HUGE_VAL);
+ atf_tc_set_md_var(tc, "descr", "Test log/f/l normal cases");
}
-
-ATF_TC(log_zero_pos);
-ATF_TC_HEAD(log_zero_pos, tc)
+ATF_TC_BODY(log_normal, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test log(+0.0) == -HUGE_VAL");
-}
+ volatile long double e = M_E;
-ATF_TC_BODY(log_zero_pos, tc)
-{
- const double x = 0.0L;
+ CHECK_EQ(0, logf, 1, 0);
+ CHECK_EQ(0, log, 1, 0);
+ CHECKL_EQ(0, logl, 1, 0);
- ATF_CHECK(log(x) == -HUGE_VAL);
-}
+ ATF_CHECK_EQ(signbit(logf(1)), 0);
+ ATF_CHECK_EQ(signbit(log(1)), 0);
+ ATF_CHECK_EQ(signbit(logl(1)), 0);
-/*
- * logf(3)
- */
-ATF_TC(logf_base);
-ATF_TC_HEAD(logf_base, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test logf(e) == 1");
+ ATF_CHECK_MSG(fabsf((logf(e) - 1)/1) < FLT_EPSILON,
+ "logf(e)=%a=%.8g", logf(e), logf(e));
+ ATF_CHECK_MSG(fabs((log(e) - 1)/1) < DBL_EPSILON,
+ "log(e)=%a=%.17g", log(e), log(e));
+ ATF_CHECK_MSG(fabsl((logl(e) - 1)/1) < LDBL_EPSILON,
+ "logl(e)=%La=%.34Lg", logl(e), logl(e));
}
-ATF_TC_BODY(logf_base, tc)
+ATF_TC(log_inf);
+ATF_TC_HEAD(log_inf, tc)
{
- const float eps = FLT_EPSILON;
-
- if (!(fabsf(logf(M_E) - 1.0f) <= eps))
- atf_tc_fail_nonfatal("logf(e) = %.17g != 1",
- (double)logf(M_E));
+ atf_tc_set_md_var(tc, "descr", "Test log/f/l on +infinity");
}
-
-ATF_TC(logf_nan);
-ATF_TC_HEAD(logf_nan, tc)
+ATF_TC_BODY(log_inf, tc)
{
- atf_tc_set_md_var(tc, "descr", "Test logf(NaN) == NaN");
-}
-ATF_TC_BODY(logf_nan, tc)
-{
- const float x = 0.0L / 0.0L;
-
- ATF_CHECK(isnan(x) != 0);
- ATF_CHECK(isnan(logf(x)) != 0);
-}
-
-ATF_TC(logf_inf_neg);
-ATF_TC_HEAD(logf_inf_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test logf(-Inf) == NaN");
-}
-
-ATF_TC_BODY(logf_inf_neg, tc)
-{
- const float x = -1.0L / 0.0L;
- const float y = logf(x);
-
- ATF_CHECK(isnan(y) != 0);
-}
-
-ATF_TC(logf_inf_pos);
-ATF_TC_HEAD(logf_inf_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test logf(+Inf) == +Inf");
-}
-
-ATF_TC_BODY(logf_inf_pos, tc)
-{
- const float x = 1.0L / 0.0L;
-
- ATF_CHECK(logf(x) == x);
-}
-
-ATF_TC(logf_one_pos);
-ATF_TC_HEAD(logf_one_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test logf(1.0) == +0.0");
-}
-
-ATF_TC_BODY(logf_one_pos, tc)
-{
- const float x = logf(1.0);
- const float y = 0.0L;
-
- ATF_CHECK(x == y);
- ATF_CHECK(signbit(x) == 0);
- ATF_CHECK(signbit(y) == 0);
-}
-
-ATF_TC(logf_zero_neg);
-ATF_TC_HEAD(logf_zero_neg, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test logf(-0.0) == -HUGE_VALF");
-}
-
-ATF_TC_BODY(logf_zero_neg, tc)
-{
- const float x = -0.0L;
-
- ATF_CHECK(logf(x) == -HUGE_VALF);
-}
-
-ATF_TC(logf_zero_pos);
-ATF_TC_HEAD(logf_zero_pos, tc)
-{
- atf_tc_set_md_var(tc, "descr", "Test logf(+0.0) == -HUGE_VALF");
-}
-
-ATF_TC_BODY(logf_zero_pos, tc)
-{
- const float x = 0.0L;
+ if (!isinf(INFINITY))
+ atf_tc_skip("no infinities on this architecture");
- ATF_CHECK(logf(x) == -HUGE_VALF);
+ CHECK_EQ(0, logf, INFINITY, INFINITY);
+ CHECK_EQ(0, log, INFINITY, INFINITY);
+ CHECKL_EQ(0, logl, INFINITY, INFINITY);
}
ATF_TP_ADD_TCS(tp)
{
- ATF_TP_ADD_TC(tp, log10_base);
- ATF_TP_ADD_TC(tp, log10_nan);
- ATF_TP_ADD_TC(tp, log10_inf_neg);
- ATF_TP_ADD_TC(tp, log10_inf_pos);
- ATF_TP_ADD_TC(tp, log10_one_pos);
- ATF_TP_ADD_TC(tp, log10_zero_neg);
- ATF_TP_ADD_TC(tp, log10_zero_pos);
-
- ATF_TP_ADD_TC(tp, log10f_base);
- ATF_TP_ADD_TC(tp, log10f_nan);
- ATF_TP_ADD_TC(tp, log10f_inf_neg);
- ATF_TP_ADD_TC(tp, log10f_inf_pos);
- ATF_TP_ADD_TC(tp, log10f_one_pos);
- ATF_TP_ADD_TC(tp, log10f_zero_neg);
- ATF_TP_ADD_TC(tp, log10f_zero_pos);
-
- ATF_TP_ADD_TC(tp, log1p_nan);
- ATF_TP_ADD_TC(tp, log1p_inf_neg);
- ATF_TP_ADD_TC(tp, log1p_inf_pos);
- ATF_TP_ADD_TC(tp, log1p_one_neg);
- ATF_TP_ADD_TC(tp, log1p_zero_neg);
- ATF_TP_ADD_TC(tp, log1p_zero_pos);
-
- ATF_TP_ADD_TC(tp, log1pf_nan);
- ATF_TP_ADD_TC(tp, log1pf_inf_neg);
- ATF_TP_ADD_TC(tp, log1pf_inf_pos);
- ATF_TP_ADD_TC(tp, log1pf_one_neg);
- ATF_TP_ADD_TC(tp, log1pf_zero_neg);
- ATF_TP_ADD_TC(tp, log1pf_zero_pos);
-
- ATF_TP_ADD_TC(tp, log2_base);
- ATF_TP_ADD_TC(tp, log2_nan);
- ATF_TP_ADD_TC(tp, log2_inf_neg);
- ATF_TP_ADD_TC(tp, log2_inf_pos);
- ATF_TP_ADD_TC(tp, log2_one_pos);
- ATF_TP_ADD_TC(tp, log2_zero_neg);
- ATF_TP_ADD_TC(tp, log2_zero_pos);
-
- ATF_TP_ADD_TC(tp, log2f_base);
- ATF_TP_ADD_TC(tp, log2f_nan);
- ATF_TP_ADD_TC(tp, log2f_inf_neg);
- ATF_TP_ADD_TC(tp, log2f_inf_pos);
- ATF_TP_ADD_TC(tp, log2f_one_pos);
- ATF_TP_ADD_TC(tp, log2f_zero_neg);
- ATF_TP_ADD_TC(tp, log2f_zero_pos);
-
- ATF_TP_ADD_TC(tp, log_base);
- ATF_TP_ADD_TC(tp, log_nan);
- ATF_TP_ADD_TC(tp, log_inf_neg);
- ATF_TP_ADD_TC(tp, log_inf_pos);
- ATF_TP_ADD_TC(tp, log_one_pos);
- ATF_TP_ADD_TC(tp, log_zero_neg);
- ATF_TP_ADD_TC(tp, log_zero_pos);
-
- ATF_TP_ADD_TC(tp, logf_base);
- ATF_TP_ADD_TC(tp, logf_nan);
- ATF_TP_ADD_TC(tp, logf_inf_neg);
- ATF_TP_ADD_TC(tp, logf_inf_pos);
- ATF_TP_ADD_TC(tp, logf_one_pos);
- ATF_TP_ADD_TC(tp, logf_zero_neg);
- ATF_TP_ADD_TC(tp, logf_zero_pos);
+ ATF_TP_ADD_TC(tp, log10_invalid);
+ ATF_TP_ADD_TC(tp, log10_zero);
+ ATF_TP_ADD_TC(tp, log10_exact);
+ ATF_TP_ADD_TC(tp, log10_inf);
+
+ ATF_TP_ADD_TC(tp, log1p_invalid);
+ ATF_TP_ADD_TC(tp, log1p_neg_one);
+ ATF_TP_ADD_TC(tp, log1p_exact);
+ ATF_TP_ADD_TC(tp, log1p_inf);
+
+ ATF_TP_ADD_TC(tp, log2_invalid);
+ ATF_TP_ADD_TC(tp, log2_zero);
+ ATF_TP_ADD_TC(tp, log2_exact);
+ ATF_TP_ADD_TC(tp, log2_inf);
+
+ ATF_TP_ADD_TC(tp, log_invalid);
+ ATF_TP_ADD_TC(tp, log_zero);
+ ATF_TP_ADD_TC(tp, log_normal);
+ ATF_TP_ADD_TC(tp, log_inf);
return atf_no_error();
}