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);

Reply via email to