tests/lib/libm/t_fe_round.c: Expand nearbyint/rint tests.

PR lib/58054
This commit is contained in:
riastradh 2024-05-03 21:40:51 +00:00
parent deeff75000
commit af8e7fd7d9
1 changed files with 314 additions and 102 deletions

View File

@ -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_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.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_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.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_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);
for (i = 0; i < __arraycount(values); i++) {
for (fn = 0; fn < N_FN; fn++) {
/*
* Set the requested rounding mode.
*/
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);
/*
* 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");
}
/* 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());
/*
* 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);
for (i = 0; i < __arraycount(values); i++) {
for (fn = 0; fn < N_FN; fn++) {
bool expect_except =
values[i].input != (double)values[i].expected;
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);
/*
* Set the requested rounding mode.
*/
fesetround(values[i].round_mode);
/* 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()));
/*
* 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);
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);
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);
/*
* Set the requested rounding mode.
*/
fesetround(valuesl[i].round_mode);
/* 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()));
/*
* 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);