Module Name: src
Committed By: riastradh
Date: Fri May 3 21:40:52 UTC 2024
Modified Files:
src/tests/lib/libm: t_fe_round.c
Log Message:
tests/lib/libm/t_fe_round.c: Expand nearbyint/rint tests.
PR lib/58054
To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/tests/lib/libm/t_fe_round.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_fe_round.c
diff -u src/tests/lib/libm/t_fe_round.c:1.15 src/tests/lib/libm/t_fe_round.c:1.16
--- src/tests/lib/libm/t_fe_round.c:1.15 Thu May 2 16:52:08 2024
+++ src/tests/lib/libm/t_fe_round.c Fri May 3 21:40:51 2024
@@ -41,108 +41,246 @@ static const struct {
double input;
long int expected;
} values[] = {
- { FE_DOWNWARD, 3.7, 3},
- { FE_DOWNWARD, -3.7, -4},
- { FE_DOWNWARD, +0, 0},
- { FE_DOWNWARD, -INT-0.01, -INT-1},
- { FE_DOWNWARD, +INT-0.01, INT-1},
- { FE_DOWNWARD, -INT+0.01, -INT},
- { FE_DOWNWARD, +INT+0.01, INT},
+ { FE_DOWNWARD, 3.75, 3},
+ { FE_DOWNWARD, -3.75, -4},
+ { FE_DOWNWARD, +0., 0},
+ { FE_DOWNWARD, -INT-0.0625, -INT-1},
+ { FE_DOWNWARD, +INT-0.0625, INT-1},
+ { FE_DOWNWARD, -INT+0.0625, -INT},
+ { FE_DOWNWARD, +INT+0.0625, INT},
#if 0 /* cpu bugs? */
- { FE_DOWNWARD, -0, -1},
+ { FE_DOWNWARD, -0., -1},
- { FE_UPWARD, +0, 1},
+ { FE_UPWARD, +0., 1},
#endif
- { FE_UPWARD, -0, 0},
- { FE_UPWARD, -123.7, -123},
- { FE_UPWARD, 123.999, 124},
- { FE_UPWARD, -INT-0.01, -INT},
- { FE_UPWARD, +INT-0.01, INT},
- { FE_UPWARD, -INT+0.01, -INT+1},
- { FE_UPWARD, +INT+0.01, INT+1},
-
- { FE_TOWARDZERO, 1.99, 1},
- { FE_TOWARDZERO, -1.99, -1},
- { FE_TOWARDZERO, 0.2, 0},
- { FE_TOWARDZERO, INT+0.01, INT},
- { FE_TOWARDZERO, INT-0.01, INT - 1},
- { FE_TOWARDZERO, -INT+0.01, -INT + 1},
- { FE_TOWARDZERO, +0, 0},
- { FE_TOWARDZERO, -0, 0},
-
- { FE_TONEAREST, -INT-0.01, -INT},
- { FE_TONEAREST, +INT-0.01, INT},
- { FE_TONEAREST, -INT+0.01, -INT},
- { FE_TONEAREST, +INT+0.01, INT},
- { FE_TONEAREST, -INT-0.501, -INT-1},
- { FE_TONEAREST, +INT-0.501, INT-1},
- { FE_TONEAREST, -INT+0.501, -INT+1},
- { FE_TONEAREST, +INT+0.501, INT+1},
- { FE_TONEAREST, +0, 0},
- { FE_TONEAREST, -0, 0},
+ { FE_UPWARD, -0., 0},
+ { FE_UPWARD, -123.75, -123},
+ { FE_UPWARD, 123.75, 124},
+ { FE_UPWARD, -INT-0.0625, -INT},
+ { FE_UPWARD, +INT-0.0625, INT},
+ { FE_UPWARD, -INT+0.0625, -INT+1},
+ { FE_UPWARD, +INT+0.0625, INT+1},
+
+ { FE_TOWARDZERO, 1.9375, 1},
+ { FE_TOWARDZERO, -1.9375, -1},
+ { FE_TOWARDZERO, 0.25, 0},
+ { FE_TOWARDZERO, INT+0.0625, INT},
+ { FE_TOWARDZERO, INT-0.0625, INT - 1},
+ { FE_TOWARDZERO, -INT+0.0625, -INT + 1},
+ { FE_TOWARDZERO, +0., 0},
+ { FE_TOWARDZERO, -0., 0},
+
+ { FE_TONEAREST, -INT-0.0625, -INT},
+ { FE_TONEAREST, +INT-0.0625, INT},
+ { FE_TONEAREST, -INT+0.0625, -INT},
+ { FE_TONEAREST, +INT+0.0625, INT},
+ { FE_TONEAREST, -INT-0.53125, -INT-1},
+ { FE_TONEAREST, +INT-0.53125, INT-1},
+ { FE_TONEAREST, -INT+0.53125, -INT+1},
+ { FE_TONEAREST, +INT+0.53125, INT+1},
+ { FE_TONEAREST, +0., 0},
+ { FE_TONEAREST, -0., 0},
};
-ATF_TC(fe_round);
-ATF_TC_HEAD(fe_round, tc)
+ATF_TC(fe_lrint);
+ATF_TC_HEAD(fe_lrint, tc)
{
- atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using lrint");
+ atf_tc_set_md_var(tc, "descr",
+ "Checking IEEE 754 rounding modes using lrint(3)");
}
-ATF_TC_BODY(fe_round, tc)
+ATF_TC_BODY(fe_lrint, tc)
{
+ enum {
+ LLRINT,
+ LLRINTF,
+ LRINT,
+ LRINTF,
+ N_FN,
+ } fn;
+ static const char *const fnname[] = {
+ [LLRINT] = "llrint",
+ [LLRINTF] = "llrintf",
+ [LRINT] = "lrint",
+ [LRINTF] = "lrintf",
+ };
long int received;
+ unsigned i;
- for (unsigned int i = 0; i < __arraycount(values); i++) {
- fesetround(values[i].round_mode);
-
- received = lrint(values[i].input);
- ATF_CHECK_MSG(
- (labs(received - values[i].expected) < EPSILON),
- "lrint rounding wrong, difference too large\n"
- "input: %f (index %d): got %ld, expected %ld\n",
- values[i].input, i, received, values[i].expected);
-
- /* Do we get the same rounding mode out? */
- ATF_CHECK_MSG(
- (fegetround() == values[i].round_mode),
- "Didn't get the same rounding mode out!\n"
- "(index %d) fed in %d rounding mode, got %d out\n",
- i, values[i].round_mode, fegetround());
+ for (i = 0; i < __arraycount(values); i++) {
+ for (fn = 0; fn < N_FN; fn++) {
+ /*
+ * Set the requested rounding mode.
+ */
+ fesetround(values[i].round_mode);
+
+ /*
+ * Call the lrint(3)-family function.
+ */
+ switch (fn) {
+ case LLRINT:
+ received = llrint(values[i].input);
+ break;
+ case LLRINTF:
+ received = llrintf(values[i].input);
+ break;
+ case LRINT:
+ received = lrint(values[i].input);
+ break;
+ case LRINTF:
+ received = lrintf(values[i].input);
+ break;
+ default:
+ atf_tc_fail("impossible");
+ }
+
+ /*
+ * Assuming the result we got has zero
+ * fractional part, casting to long int should
+ * have no rounding. Verify it matches the
+ * integer we expect.
+ */
+ ATF_CHECK_MSG((long int)received == values[i].expected,
+ "[%u] %s %s(%f): got %ld, expected %ld",
+ i, rmname(values[i].round_mode), fnname[fn],
+ values[i].input,
+ (long int)received, values[i].expected);
+
+ /* Do we get the same rounding mode out? */
+ ATF_CHECK_MSG(fegetround() == values[i].round_mode,
+ "[%u] %s: set %d (%s), got %d (%s)",
+ i, fnname[fn],
+ values[i].round_mode, rmname(values[i].round_mode),
+ fegetround(), rmname(fegetround()));
+ }
}
}
-ATF_TC(fe_nearbyint);
-ATF_TC_HEAD(fe_nearbyint, tc)
+ATF_TC(fe_nearbyint_rint);
+ATF_TC_HEAD(fe_nearbyint_rint, tc)
{
atf_tc_set_md_var(tc, "descr",
- "Checking IEEE 754 rounding modes using nearbyint");
+ "Checking IEEE 754 rounding modes using nearbyint/rint");
}
-ATF_TC_BODY(fe_nearbyint, tc)
+ATF_TC_BODY(fe_nearbyint_rint, tc)
{
+ enum {
+ NEARBYINT,
+ NEARBYINTF,
+ NEARBYINTL,
+ RINT,
+ RINTF,
+ RINTL,
+ N_FN,
+ } fn;
+ static const char *const fnname[] = {
+ [NEARBYINT] = "nearbyint",
+ [NEARBYINTF] = "nearbyintf",
+ [NEARBYINTL] = "nearbyintl",
+ [RINT] = "rint",
+ [RINTF] = "rintf",
+ [RINTL] = "rintl",
+ };
double received, ipart, fpart;
+ unsigned i;
- for (unsigned int i = 0; i < __arraycount(values); i++) {
- fesetround(values[i].round_mode);
-
- received = nearbyint(values[i].input);
- fpart = modf(received, &ipart);
- ATF_CHECK_MSG(fpart == 0,
- "[%u] %s nearbyint(%f) has fractional part %f"
- " (integer part %f)",
- i, rmname(values[i].round_mode), values[i].input, fpart,
- ipart);
- ATF_CHECK_MSG((long int)received == values[i].expected,
- "[%u] %s nearbyint(%f): got %f, expected %ld",
- i, rmname(values[i].round_mode),
- values[i].input, received, values[i].expected);
-
- /* Do we get the same rounding mode out? */
- ATF_CHECK_MSG(fegetround() == values[i].round_mode,
- "[%u] set %d (%s), got %d (%s)",
- i,
- values[i].round_mode, rmname(values[i].round_mode),
- fegetround(), rmname(fegetround()));
+ for (i = 0; i < __arraycount(values); i++) {
+ for (fn = 0; fn < N_FN; fn++) {
+ bool expect_except =
+ values[i].input != (double)values[i].expected;
+
+ /*
+ * Set the requested rounding mode.
+ */
+ fesetround(values[i].round_mode);
+
+ /*
+ * Clear sticky floating-point exception bits
+ * so we can verify whether the FE_INEXACT
+ * exception is raised.
+ */
+ feclearexcept(FE_ALL_EXCEPT);
+
+ /*
+ * Call the rint(3)-family function.
+ */
+ switch (fn) {
+ case NEARBYINT:
+ received = nearbyint(values[i].input);
+ expect_except = false;
+ break;
+ case NEARBYINTF:
+ received = nearbyintf(values[i].input);
+ expect_except = false;
+ break;
+ case NEARBYINTL:
+ received = nearbyintl(values[i].input);
+ expect_except = false;
+ break;
+ case RINT:
+ received = rint(values[i].input);
+ break;
+ case RINTF:
+ received = rintf(values[i].input);
+ break;
+ case RINTL:
+ received = rintl(values[i].input);
+ break;
+ default:
+ atf_tc_fail("impossible");
+ }
+
+ /*
+ * Verify FE_INEXACT was raised or not,
+ * depending on whether there was rounding and
+ * whether the function is supposed to raise
+ * exceptions.
+ */
+ if (expect_except) {
+ ATF_CHECK_MSG(fetestexcept(FE_INEXACT) != 0,
+ "[%u] %s %s(%f)"
+ " failed to raise FE_INEXACT",
+ i, rmname(values[i].round_mode),
+ fnname[fn], values[i].input);
+ } else {
+ ATF_CHECK_MSG(fetestexcept(FE_INEXACT) == 0,
+ "[%u] %s %s(%f)"
+ " spuriously raised FE_INEXACT",
+ i, rmname(values[i].round_mode),
+ fnname[fn], values[i].input);
+ }
+
+ /*
+ * Verify the fractional part of the result is
+ * zero -- the result of rounding to an integer
+ * is supposed to be an integer.
+ */
+ fpart = modf(received, &ipart);
+ ATF_CHECK_MSG(fpart == 0,
+ "[%u] %s %s(%f)=%f has fractional part %f"
+ " (integer part %f)",
+ i, rmname(values[i].round_mode), fnname[fn],
+ values[i].input, received, fpart, ipart);
+
+ /*
+ * Assuming the result we got has zero
+ * fractional part, casting to long int should
+ * have no rounding. Verify it matches the
+ * integer we expect.
+ */
+ ATF_CHECK_MSG((long int)received == values[i].expected,
+ "[%u] %s %s(%f): got %f, expected %ld",
+ i, rmname(values[i].round_mode), fnname[fn],
+ values[i].input, received, values[i].expected);
+
+ /* Do we get the same rounding mode out? */
+ ATF_CHECK_MSG(fegetround() == values[i].round_mode,
+ "[%u] %s: set %d (%s), got %d (%s)",
+ i, fnname[fn],
+ values[i].round_mode, rmname(values[i].round_mode),
+ fegetround(), rmname(fegetround()));
+ }
}
}
@@ -154,7 +292,7 @@ ATF_TC_BODY(fe_nearbyint, tc)
static const struct {
int round_mode;
long double input;
- intmax_t expected;
+ int64_t expected;
} valuesl[] = {
{ FE_TOWARDZERO, 0x2.00000000000008p+52L, 0x20000000000000 },
{ FE_DOWNWARD, 0x2.00000000000008p+52L, 0x20000000000000 },
@@ -166,38 +304,112 @@ static const struct {
{ FE_TONEAREST, 0x2.00000000000018p+52L, 0x20000000000002 },
};
-ATF_TC(fe_nearbyintl);
-ATF_TC_HEAD(fe_nearbyintl, tc)
+ATF_TC(fe_nearbyintl_rintl);
+ATF_TC_HEAD(fe_nearbyintl_rintl, tc)
{
atf_tc_set_md_var(tc, "descr",
- "Checking IEEE 754 rounding modes using nearbyintl");
+ "Checking IEEE 754 rounding modes using nearbyintl/rintl");
}
-ATF_TC_BODY(fe_nearbyintl, tc)
+ATF_TC_BODY(fe_nearbyintl_rintl, tc)
{
+ enum {
+ RINTL,
+ NEARBYINTL,
+ N_FN,
+ } fn;
+ static const char *const fnname[] = {
+ [RINTL] = "rintl",
+ [NEARBYINTL] = "nearbyintl",
+ };
long double received, ipart, fpart;
+ unsigned i;
- for (unsigned int i = 0; i < __arraycount(valuesl); i++) {
- fesetround(valuesl[i].round_mode);
-
- received = nearbyintl(valuesl[i].input);
- fpart = modfl(received, &ipart);
- ATF_CHECK_MSG(fpart == 0,
- "[%u] %s nearbyintl(%Lf) has fractional part %Lf"
- " (integer part %Lf)",
- i, rmname(valuesl[i].round_mode), valuesl[i].input, fpart,
- ipart);
- ATF_CHECK_MSG((intmax_t)received == valuesl[i].expected,
- "[%u] %s nearbyintl(%Lf): got %Lf, expected %jd",
- i, rmname(valuesl[i].round_mode),
- valuesl[i].input, received, valuesl[i].expected);
-
- /* Do we get the same rounding mode out? */
- ATF_CHECK_MSG(fegetround() == valuesl[i].round_mode,
- "[%u] set %d (%s), got %d (%s)",
- i,
- valuesl[i].round_mode, rmname(valuesl[i].round_mode),
- fegetround(), rmname(fegetround()));
+ for (i = 0; i < __arraycount(valuesl); i++) {
+ for (fn = 0; fn < N_FN; fn++) {
+ bool expect_except =
+ (valuesl[i].input !=
+ (long double)valuesl[i].expected);
+
+ /*
+ * Set the requested rounding mode.
+ */
+ fesetround(valuesl[i].round_mode);
+
+ /*
+ * Clear sticky floating-point exception bits
+ * so we can verify whether the FE_INEXACT
+ * exception is raised.
+ */
+ feclearexcept(FE_ALL_EXCEPT);
+
+ /*
+ * Call the rint(3)-family function.
+ */
+ switch (fn) {
+ case NEARBYINTL:
+ received = nearbyintl(valuesl[i].input);
+ expect_except = false;
+ break;
+ case RINTL:
+ received = rintl(valuesl[i].input);
+ break;
+ default:
+ atf_tc_fail("impossible");
+ }
+
+ /*
+ * Verify FE_INEXACT was raised or not,
+ * depending on whether there was rounding and
+ * whether the function is supposed to raise
+ * exceptions.
+ */
+ if (expect_except) {
+ ATF_CHECK_MSG(fetestexcept(FE_INEXACT) != 0,
+ "[%u] %s %s(%Lf)"
+ " failed to raise FE_INEXACT",
+ i, rmname(valuesl[i].round_mode),
+ fnname[fn], valuesl[i].input);
+ } else {
+ ATF_CHECK_MSG(fetestexcept(FE_INEXACT) == 0,
+ "[%u] %s %s(%Lf)"
+ " spuriously raised FE_INEXACT",
+ i, rmname(valuesl[i].round_mode),
+ fnname[fn], valuesl[i].input);
+ }
+
+ /*
+ * Verify the fractional part of the result is
+ * zero -- the result of rounding to an integer
+ * is supposed to be an integer.
+ */
+ fpart = modfl(received, &ipart);
+ ATF_CHECK_MSG(fpart == 0,
+ "[%u] %s %s(%Lf)=%Lf has fractional part %Lf"
+ " (integer part %Lf)",
+ i, rmname(valuesl[i].round_mode), fnname[fn],
+ valuesl[i].input, received, fpart, ipart);
+
+ /*
+ * Assuming the result we got has zero
+ * fractional part, casting to int64_t should
+ * have no rounding. Verify it matches the
+ * integer we expect.
+ */
+ ATF_CHECK_MSG(((int64_t)received ==
+ valuesl[i].expected),
+ "[%u] %s %s(%Lf): got %Lf, expected %jd",
+ i, rmname(valuesl[i].round_mode), fnname[fn],
+ valuesl[i].input, received, valuesl[i].expected);
+
+ /* Do we get the same rounding mode out? */
+ ATF_CHECK_MSG(fegetround() == valuesl[i].round_mode,
+ "[%u] %s: set %d (%s), got %d (%s)",
+ i, fnname[fn],
+ valuesl[i].round_mode,
+ rmname(valuesl[i].round_mode),
+ fegetround(), rmname(fegetround()));
+ }
}
}
@@ -267,10 +479,10 @@ ATF_TC_BODY(fe_nexttoward, tc)
ATF_TP_ADD_TCS(tp)
{
- ATF_TP_ADD_TC(tp, fe_round);
- ATF_TP_ADD_TC(tp, fe_nearbyint);
+ ATF_TP_ADD_TC(tp, fe_lrint);
+ ATF_TP_ADD_TC(tp, fe_nearbyint_rint);
#ifdef __HAVE_LONG_DOUBLE
- ATF_TP_ADD_TC(tp, fe_nearbyintl);
+ ATF_TP_ADD_TC(tp, fe_nearbyintl_rintl);
#endif
ATF_TP_ADD_TC(tp, fe_nextafter);
ATF_TP_ADD_TC(tp, fe_nexttoward);