xref: /netbsd-src/tests/lib/libm/t_fe_round.c (revision 906e271cb392171a4b91e8a35d76013244a2813f)
1*906e271cSriastradh /*	$NetBSD: t_fe_round.c,v 1.20 2024/05/15 00:02:57 riastradh Exp $	*/
220b05e74Sriastradh 
3377c57d5Smaya /*
4377c57d5Smaya  * Written by Maya Rashish <maya@NetBSD.org>
5377c57d5Smaya  * Public domain.
6377c57d5Smaya  *
7377c57d5Smaya  * Testing IEEE-754 rounding modes (and lrint)
8377c57d5Smaya  */
9377c57d5Smaya 
1020b05e74Sriastradh #include <sys/cdefs.h>
11*906e271cSriastradh __RCSID("$NetBSD: t_fe_round.c,v 1.20 2024/05/15 00:02:57 riastradh Exp $");
1220b05e74Sriastradh 
13377c57d5Smaya #include <atf-c.h>
14377c57d5Smaya #include <fenv.h>
15377c57d5Smaya #include <math.h>
16483439ecSkre #include <stdint.h>
17377c57d5Smaya #include <stdio.h>
18377c57d5Smaya #include <stdlib.h>
19377c57d5Smaya 
2020b05e74Sriastradh #ifdef __HAVE_FENV
2120b05e74Sriastradh 
22377c57d5Smaya /*#pragma STDC FENV_ACCESS ON gcc?? */
23377c57d5Smaya 
24377c57d5Smaya #define INT 9223L
25377c57d5Smaya 
2602e4b613Sriastradh static const char *
rmname(int rm)2702e4b613Sriastradh rmname(int rm)
2802e4b613Sriastradh {
2902e4b613Sriastradh 	switch (rm) {
3002e4b613Sriastradh 	case FE_TOWARDZERO:
3102e4b613Sriastradh 		return "FE_TOWARDZERO";
3202e4b613Sriastradh 	case FE_DOWNWARD:
3302e4b613Sriastradh 		return "FE_DOWNWARD";
3402e4b613Sriastradh 	case FE_UPWARD:
3502e4b613Sriastradh 		return "FE_UPWARD";
3602e4b613Sriastradh 	case FE_TONEAREST:
3702e4b613Sriastradh 		return "FE_TONEAREST";
3802e4b613Sriastradh 	default:
3902e4b613Sriastradh 		return "unknown";
4002e4b613Sriastradh 	}
4102e4b613Sriastradh }
4202e4b613Sriastradh 
4320b05e74Sriastradh /*
4420b05e74Sriastradh  * Examples are chosen to fit within the smallest single-precision
4520b05e74Sriastradh  * format any NetBSD port uses, so that we can write the examples once
4620b05e74Sriastradh  * in type double, and convert to single without raising inexact-result
4720b05e74Sriastradh  * exceptions when we're trying to test whether the integer-rounding
4820b05e74Sriastradh  * functions raise them.
4920b05e74Sriastradh  */
50377c57d5Smaya static const struct {
51377c57d5Smaya 	int round_mode;
52377c57d5Smaya 	double input;
53377c57d5Smaya 	long int expected;
54377c57d5Smaya } values[] = {
55af8e7fd7Sriastradh 	{ FE_DOWNWARD,		3.75,		3},
56af8e7fd7Sriastradh 	{ FE_DOWNWARD,		-3.75,		-4},
57af8e7fd7Sriastradh 	{ FE_DOWNWARD,		+0.,		0},
5820b05e74Sriastradh 	{ FE_DOWNWARD,		-0.,		0},
59af8e7fd7Sriastradh 	{ FE_DOWNWARD,		-INT-0.0625,	-INT-1},
60af8e7fd7Sriastradh 	{ FE_DOWNWARD,		+INT-0.0625,	INT-1},
61af8e7fd7Sriastradh 	{ FE_DOWNWARD,		-INT+0.0625,	-INT},
62af8e7fd7Sriastradh 	{ FE_DOWNWARD,		+INT+0.0625,	INT},
63377c57d5Smaya 
6420b05e74Sriastradh 	{ FE_UPWARD,		+0.,		0},
65af8e7fd7Sriastradh 	{ FE_UPWARD,		-0.,		0},
66af8e7fd7Sriastradh 	{ FE_UPWARD,		-123.75,	-123},
67af8e7fd7Sriastradh 	{ FE_UPWARD,		123.75,		124},
68af8e7fd7Sriastradh 	{ FE_UPWARD,		-INT-0.0625,	-INT},
69af8e7fd7Sriastradh 	{ FE_UPWARD,		+INT-0.0625,	INT},
70af8e7fd7Sriastradh 	{ FE_UPWARD,		-INT+0.0625,	-INT+1},
71af8e7fd7Sriastradh 	{ FE_UPWARD,		+INT+0.0625,	INT+1},
72377c57d5Smaya 
73af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	1.9375,		1},
74af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	-1.9375,	-1},
75af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	0.25,		0},
76af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	INT+0.0625,	INT},
77af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	INT-0.0625,	INT - 1},
78af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	-INT+0.0625,	-INT + 1},
79af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	+0.,		0},
80af8e7fd7Sriastradh 	{ FE_TOWARDZERO,	-0.,		0},
81377c57d5Smaya 
82af8e7fd7Sriastradh 	{ FE_TONEAREST,		-INT-0.0625,	-INT},
83af8e7fd7Sriastradh 	{ FE_TONEAREST,		+INT-0.0625,	INT},
84af8e7fd7Sriastradh 	{ FE_TONEAREST,		-INT+0.0625,	-INT},
85af8e7fd7Sriastradh 	{ FE_TONEAREST,		+INT+0.0625,	INT},
86af8e7fd7Sriastradh 	{ FE_TONEAREST,		-INT-0.53125,	-INT-1},
87af8e7fd7Sriastradh 	{ FE_TONEAREST,		+INT-0.53125,	INT-1},
88af8e7fd7Sriastradh 	{ FE_TONEAREST,		-INT+0.53125,	-INT+1},
89af8e7fd7Sriastradh 	{ FE_TONEAREST,		+INT+0.53125,	INT+1},
90af8e7fd7Sriastradh 	{ FE_TONEAREST,		+0.,		0},
91af8e7fd7Sriastradh 	{ FE_TONEAREST,		-0.,		0},
92377c57d5Smaya };
93377c57d5Smaya 
94af8e7fd7Sriastradh ATF_TC(fe_lrint);
ATF_TC_HEAD(fe_lrint,tc)95af8e7fd7Sriastradh ATF_TC_HEAD(fe_lrint, tc)
9686dc433aShe {
9702e4b613Sriastradh 	atf_tc_set_md_var(tc, "descr",
98af8e7fd7Sriastradh 	    "Checking IEEE 754 rounding modes using lrint(3)");
9986dc433aShe }
10086dc433aShe 
ATF_TC_BODY(fe_lrint,tc)101af8e7fd7Sriastradh ATF_TC_BODY(fe_lrint, tc)
10286dc433aShe {
103af8e7fd7Sriastradh 	enum {
104af8e7fd7Sriastradh 		LLRINT,
105af8e7fd7Sriastradh 		LLRINTF,
106af8e7fd7Sriastradh 		LRINT,
107af8e7fd7Sriastradh 		LRINTF,
108af8e7fd7Sriastradh 		N_FN,
109af8e7fd7Sriastradh 	} fn;
110af8e7fd7Sriastradh 	static const char *const fnname[] = {
111af8e7fd7Sriastradh 		[LLRINT] = "llrint",
112af8e7fd7Sriastradh 		[LLRINTF] = "llrintf",
113af8e7fd7Sriastradh 		[LRINT] = "lrint",
114af8e7fd7Sriastradh 		[LRINTF] = "lrintf",
115af8e7fd7Sriastradh 	};
116af8e7fd7Sriastradh 	long int received;
117af8e7fd7Sriastradh 	unsigned i;
11886dc433aShe 
119af8e7fd7Sriastradh 	for (i = 0; i < __arraycount(values); i++) {
120af8e7fd7Sriastradh 		for (fn = 0; fn < N_FN; fn++) {
121af8e7fd7Sriastradh 			/*
122af8e7fd7Sriastradh 			 * Set the requested rounding mode.
123af8e7fd7Sriastradh 			 */
12486dc433aShe 			fesetround(values[i].round_mode);
12586dc433aShe 
126af8e7fd7Sriastradh 			/*
127af8e7fd7Sriastradh 			 * Call the lrint(3)-family function.
128af8e7fd7Sriastradh 			 */
129af8e7fd7Sriastradh 			switch (fn) {
130af8e7fd7Sriastradh 			case LLRINT:
131af8e7fd7Sriastradh 				received = llrint(values[i].input);
132af8e7fd7Sriastradh 				break;
133af8e7fd7Sriastradh 			case LLRINTF:
134af8e7fd7Sriastradh 				received = llrintf(values[i].input);
135af8e7fd7Sriastradh 				break;
136af8e7fd7Sriastradh 			case LRINT:
137af8e7fd7Sriastradh 				received = lrint(values[i].input);
138af8e7fd7Sriastradh 				break;
139af8e7fd7Sriastradh 			case LRINTF:
140af8e7fd7Sriastradh 				received = lrintf(values[i].input);
141af8e7fd7Sriastradh 				break;
142af8e7fd7Sriastradh 			default:
143af8e7fd7Sriastradh 				atf_tc_fail("impossible");
144af8e7fd7Sriastradh 			}
145af8e7fd7Sriastradh 
146af8e7fd7Sriastradh 			/*
147af8e7fd7Sriastradh 			 * Assuming the result we got has zero
148af8e7fd7Sriastradh 			 * fractional part, casting to long int should
149af8e7fd7Sriastradh 			 * have no rounding.  Verify it matches the
150af8e7fd7Sriastradh 			 * integer we expect.
151af8e7fd7Sriastradh 			 */
152af8e7fd7Sriastradh 			ATF_CHECK_MSG((long int)received == values[i].expected,
153af8e7fd7Sriastradh 			    "[%u] %s %s(%f): got %ld, expected %ld",
154af8e7fd7Sriastradh 			    i, rmname(values[i].round_mode), fnname[fn],
155af8e7fd7Sriastradh 			    values[i].input,
156af8e7fd7Sriastradh 			    (long int)received, values[i].expected);
157af8e7fd7Sriastradh 
158af8e7fd7Sriastradh 			/* Do we get the same rounding mode out? */
159af8e7fd7Sriastradh 			ATF_CHECK_MSG(fegetround() == values[i].round_mode,
160af8e7fd7Sriastradh 			    "[%u] %s: set %d (%s), got %d (%s)",
161af8e7fd7Sriastradh 			    i, fnname[fn],
162af8e7fd7Sriastradh 			    values[i].round_mode, rmname(values[i].round_mode),
163af8e7fd7Sriastradh 			    fegetround(), rmname(fegetround()));
164af8e7fd7Sriastradh 		}
165af8e7fd7Sriastradh 	}
166af8e7fd7Sriastradh }
167af8e7fd7Sriastradh 
168af8e7fd7Sriastradh ATF_TC(fe_nearbyint_rint);
ATF_TC_HEAD(fe_nearbyint_rint,tc)169af8e7fd7Sriastradh ATF_TC_HEAD(fe_nearbyint_rint, tc)
170af8e7fd7Sriastradh {
171af8e7fd7Sriastradh 	atf_tc_set_md_var(tc, "descr",
172af8e7fd7Sriastradh 	    "Checking IEEE 754 rounding modes using nearbyint/rint");
173af8e7fd7Sriastradh }
174af8e7fd7Sriastradh 
ATF_TC_BODY(fe_nearbyint_rint,tc)175af8e7fd7Sriastradh ATF_TC_BODY(fe_nearbyint_rint, tc)
176af8e7fd7Sriastradh {
177af8e7fd7Sriastradh 	enum {
178af8e7fd7Sriastradh 		NEARBYINT,
179af8e7fd7Sriastradh 		NEARBYINTF,
180af8e7fd7Sriastradh 		NEARBYINTL,
181af8e7fd7Sriastradh 		RINT,
182af8e7fd7Sriastradh 		RINTF,
183af8e7fd7Sriastradh 		RINTL,
184af8e7fd7Sriastradh 		N_FN,
185af8e7fd7Sriastradh 	} fn;
186af8e7fd7Sriastradh 	static const char *const fnname[] = {
187af8e7fd7Sriastradh 		[NEARBYINT] = "nearbyint",
188af8e7fd7Sriastradh 		[NEARBYINTF] = "nearbyintf",
189af8e7fd7Sriastradh 		[NEARBYINTL] = "nearbyintl",
190af8e7fd7Sriastradh 		[RINT] = "rint",
191af8e7fd7Sriastradh 		[RINTF] = "rintf",
192af8e7fd7Sriastradh 		[RINTL] = "rintl",
193af8e7fd7Sriastradh 	};
194af8e7fd7Sriastradh 	double received, ipart, fpart;
195af8e7fd7Sriastradh 	unsigned i;
196af8e7fd7Sriastradh 
197af8e7fd7Sriastradh 	for (i = 0; i < __arraycount(values); i++) {
198af8e7fd7Sriastradh 		for (fn = 0; fn < N_FN; fn++) {
199af8e7fd7Sriastradh 			bool expect_except =
200af8e7fd7Sriastradh 			    values[i].input != (double)values[i].expected;
201af8e7fd7Sriastradh 
202af8e7fd7Sriastradh 			/*
203af8e7fd7Sriastradh 			 * Set the requested rounding mode.
204af8e7fd7Sriastradh 			 */
205af8e7fd7Sriastradh 			fesetround(values[i].round_mode);
206af8e7fd7Sriastradh 
2072b70237dSriastradh #ifdef __ia64__
2082b70237dSriastradh /*
2092b70237dSriastradh  * Without this barrier, we get:
2102b70237dSriastradh  *
2112b70237dSriastradh  * /tmp//ccJayu9g.s:2793: Warning: Use of 'mov.m' violates RAW dependency 'AR[FPSR].sf0.flags' (impliedf)
2122b70237dSriastradh  * /tmp//ccJayu9g.s:2793: Warning: Only the first path encountering the conflict is reported
2132b70237dSriastradh  * /tmp//ccJayu9g.s:2757: Warning: This is the location of the conflicting usage
2142b70237dSriastradh  *
2152b70237dSriastradh  * (If you fix this, remove the entry from doc/HACKS.)
2162b70237dSriastradh  */
2172b70237dSriastradh 			__insn_barrier();
2182b70237dSriastradh #endif
2192b70237dSriastradh 
220af8e7fd7Sriastradh 			/*
221af8e7fd7Sriastradh 			 * Clear sticky floating-point exception bits
222af8e7fd7Sriastradh 			 * so we can verify whether the FE_INEXACT
223af8e7fd7Sriastradh 			 * exception is raised.
224af8e7fd7Sriastradh 			 */
225af8e7fd7Sriastradh 			feclearexcept(FE_ALL_EXCEPT);
226af8e7fd7Sriastradh 
227af8e7fd7Sriastradh 			/*
228af8e7fd7Sriastradh 			 * Call the rint(3)-family function.
229af8e7fd7Sriastradh 			 */
230af8e7fd7Sriastradh 			switch (fn) {
231af8e7fd7Sriastradh 			case NEARBYINT:
23286dc433aShe 				received = nearbyint(values[i].input);
233af8e7fd7Sriastradh 				expect_except = false;
234af8e7fd7Sriastradh 				break;
235af8e7fd7Sriastradh 			case NEARBYINTF:
236af8e7fd7Sriastradh 				received = nearbyintf(values[i].input);
237af8e7fd7Sriastradh 				expect_except = false;
238af8e7fd7Sriastradh 				break;
239af8e7fd7Sriastradh 			case NEARBYINTL:
240af8e7fd7Sriastradh 				received = nearbyintl(values[i].input);
241af8e7fd7Sriastradh 				expect_except = false;
242af8e7fd7Sriastradh 				break;
243af8e7fd7Sriastradh 			case RINT:
244af8e7fd7Sriastradh 				received = rint(values[i].input);
245af8e7fd7Sriastradh 				break;
246af8e7fd7Sriastradh 			case RINTF:
247af8e7fd7Sriastradh 				received = rintf(values[i].input);
248af8e7fd7Sriastradh 				break;
249af8e7fd7Sriastradh 			case RINTL:
250af8e7fd7Sriastradh 				received = rintl(values[i].input);
251af8e7fd7Sriastradh 				break;
252af8e7fd7Sriastradh 			default:
253af8e7fd7Sriastradh 				atf_tc_fail("impossible");
254af8e7fd7Sriastradh 			}
255af8e7fd7Sriastradh 
256af8e7fd7Sriastradh 			/*
257af8e7fd7Sriastradh 			 * Verify FE_INEXACT was raised or not,
258af8e7fd7Sriastradh 			 * depending on whether there was rounding and
259af8e7fd7Sriastradh 			 * whether the function is supposed to raise
260af8e7fd7Sriastradh 			 * exceptions.
261af8e7fd7Sriastradh 			 */
262af8e7fd7Sriastradh 			if (expect_except) {
263af8e7fd7Sriastradh 				ATF_CHECK_MSG(fetestexcept(FE_INEXACT) != 0,
264af8e7fd7Sriastradh 				    "[%u] %s %s(%f)"
265af8e7fd7Sriastradh 				    " failed to raise FE_INEXACT",
266af8e7fd7Sriastradh 				    i, rmname(values[i].round_mode),
267af8e7fd7Sriastradh 				    fnname[fn], values[i].input);
268af8e7fd7Sriastradh 			} else {
269af8e7fd7Sriastradh 				ATF_CHECK_MSG(fetestexcept(FE_INEXACT) == 0,
270af8e7fd7Sriastradh 				    "[%u] %s %s(%f)"
271af8e7fd7Sriastradh 				    " spuriously raised FE_INEXACT",
272af8e7fd7Sriastradh 				    i, rmname(values[i].round_mode),
273af8e7fd7Sriastradh 				    fnname[fn], values[i].input);
274af8e7fd7Sriastradh 			}
275af8e7fd7Sriastradh 
276af8e7fd7Sriastradh 			/*
277af8e7fd7Sriastradh 			 * Verify the fractional part of the result is
278af8e7fd7Sriastradh 			 * zero -- the result of rounding to an integer
279af8e7fd7Sriastradh 			 * is supposed to be an integer.
280af8e7fd7Sriastradh 			 */
28102e4b613Sriastradh 			fpart = modf(received, &ipart);
28202e4b613Sriastradh 			ATF_CHECK_MSG(fpart == 0,
283af8e7fd7Sriastradh 			    "[%u] %s %s(%f)=%f has fractional part %f"
2842bd651d9Sriastradh 			    " (integer part %f)",
285af8e7fd7Sriastradh 			    i, rmname(values[i].round_mode), fnname[fn],
286af8e7fd7Sriastradh 			    values[i].input, received, fpart, ipart);
287af8e7fd7Sriastradh 
288af8e7fd7Sriastradh 			/*
289af8e7fd7Sriastradh 			 * Assuming the result we got has zero
290af8e7fd7Sriastradh 			 * fractional part, casting to long int should
291af8e7fd7Sriastradh 			 * have no rounding.  Verify it matches the
292af8e7fd7Sriastradh 			 * integer we expect.
293af8e7fd7Sriastradh 			 */
29402e4b613Sriastradh 			ATF_CHECK_MSG((long int)received == values[i].expected,
295af8e7fd7Sriastradh 			    "[%u] %s %s(%f): got %f, expected %ld",
296af8e7fd7Sriastradh 			    i, rmname(values[i].round_mode), fnname[fn],
2972bd651d9Sriastradh 			    values[i].input, received, values[i].expected);
29886dc433aShe 
29986dc433aShe 			/* Do we get the same rounding mode out? */
30002e4b613Sriastradh 			ATF_CHECK_MSG(fegetround() == values[i].round_mode,
301af8e7fd7Sriastradh 			    "[%u] %s: set %d (%s), got %d (%s)",
302af8e7fd7Sriastradh 			    i, fnname[fn],
30302e4b613Sriastradh 			    values[i].round_mode, rmname(values[i].round_mode),
30402e4b613Sriastradh 			    fegetround(), rmname(fegetround()));
30586dc433aShe 		}
30686dc433aShe 	}
307af8e7fd7Sriastradh }
30886dc433aShe 
309247fbbb1Sriastradh #ifdef __HAVE_LONG_DOUBLE
310247fbbb1Sriastradh 
311247fbbb1Sriastradh /*
312247fbbb1Sriastradh  * Use one bit more than fits in IEEE 754 binary64.
313247fbbb1Sriastradh  */
314247fbbb1Sriastradh static const struct {
315247fbbb1Sriastradh 	int round_mode;
316247fbbb1Sriastradh 	long double input;
317af8e7fd7Sriastradh 	int64_t expected;
318247fbbb1Sriastradh } valuesl[] = {
31938aebf98Sriastradh 	{ FE_TOWARDZERO,	0x2.00000000000008p+52L, 0x20000000000000 },
32038aebf98Sriastradh 	{ FE_DOWNWARD,		0x2.00000000000008p+52L, 0x20000000000000 },
32138aebf98Sriastradh 	{ FE_UPWARD,		0x2.00000000000008p+52L, 0x20000000000001 },
32238aebf98Sriastradh 	{ FE_TONEAREST,		0x2.00000000000008p+52L, 0x20000000000000 },
32338aebf98Sriastradh 	{ FE_TOWARDZERO,	0x2.00000000000018p+52L, 0x20000000000001 },
32438aebf98Sriastradh 	{ FE_DOWNWARD,		0x2.00000000000018p+52L, 0x20000000000001 },
32538aebf98Sriastradh 	{ FE_UPWARD,		0x2.00000000000018p+52L, 0x20000000000002 },
32638aebf98Sriastradh 	{ FE_TONEAREST,		0x2.00000000000018p+52L, 0x20000000000002 },
327247fbbb1Sriastradh };
328247fbbb1Sriastradh 
329af8e7fd7Sriastradh ATF_TC(fe_nearbyintl_rintl);
ATF_TC_HEAD(fe_nearbyintl_rintl,tc)330af8e7fd7Sriastradh ATF_TC_HEAD(fe_nearbyintl_rintl, tc)
331247fbbb1Sriastradh {
332247fbbb1Sriastradh 	atf_tc_set_md_var(tc, "descr",
333af8e7fd7Sriastradh 	    "Checking IEEE 754 rounding modes using nearbyintl/rintl");
334247fbbb1Sriastradh }
335247fbbb1Sriastradh 
ATF_TC_BODY(fe_nearbyintl_rintl,tc)336af8e7fd7Sriastradh ATF_TC_BODY(fe_nearbyintl_rintl, tc)
337247fbbb1Sriastradh {
338af8e7fd7Sriastradh 	enum {
339af8e7fd7Sriastradh 		RINTL,
340af8e7fd7Sriastradh 		NEARBYINTL,
341af8e7fd7Sriastradh 		N_FN,
342af8e7fd7Sriastradh 	} fn;
343af8e7fd7Sriastradh 	static const char *const fnname[] = {
344af8e7fd7Sriastradh 		[RINTL] = "rintl",
345af8e7fd7Sriastradh 		[NEARBYINTL] = "nearbyintl",
346af8e7fd7Sriastradh 	};
347247fbbb1Sriastradh 	long double received, ipart, fpart;
348af8e7fd7Sriastradh 	unsigned i;
349247fbbb1Sriastradh 
350af8e7fd7Sriastradh 	for (i = 0; i < __arraycount(valuesl); i++) {
351af8e7fd7Sriastradh 		for (fn = 0; fn < N_FN; fn++) {
352af8e7fd7Sriastradh 			bool expect_except =
353af8e7fd7Sriastradh 			    (valuesl[i].input !=
354af8e7fd7Sriastradh 				(long double)valuesl[i].expected);
355af8e7fd7Sriastradh 
356af8e7fd7Sriastradh 			/*
357af8e7fd7Sriastradh 			 * Set the requested rounding mode.
358af8e7fd7Sriastradh 			 */
359247fbbb1Sriastradh 			fesetround(valuesl[i].round_mode);
360247fbbb1Sriastradh 
361af8e7fd7Sriastradh 			/*
362af8e7fd7Sriastradh 			 * Clear sticky floating-point exception bits
363af8e7fd7Sriastradh 			 * so we can verify whether the FE_INEXACT
364af8e7fd7Sriastradh 			 * exception is raised.
365af8e7fd7Sriastradh 			 */
366af8e7fd7Sriastradh 			feclearexcept(FE_ALL_EXCEPT);
367af8e7fd7Sriastradh 
368af8e7fd7Sriastradh 			/*
369af8e7fd7Sriastradh 			 * Call the rint(3)-family function.
370af8e7fd7Sriastradh 			 */
371af8e7fd7Sriastradh 			switch (fn) {
372af8e7fd7Sriastradh 			case NEARBYINTL:
373247fbbb1Sriastradh 				received = nearbyintl(valuesl[i].input);
374af8e7fd7Sriastradh 				expect_except = false;
375af8e7fd7Sriastradh 				break;
376af8e7fd7Sriastradh 			case RINTL:
377af8e7fd7Sriastradh 				received = rintl(valuesl[i].input);
378af8e7fd7Sriastradh 				break;
379af8e7fd7Sriastradh 			default:
380af8e7fd7Sriastradh 				atf_tc_fail("impossible");
381af8e7fd7Sriastradh 			}
382af8e7fd7Sriastradh 
383af8e7fd7Sriastradh 			/*
384af8e7fd7Sriastradh 			 * Verify FE_INEXACT was raised or not,
385af8e7fd7Sriastradh 			 * depending on whether there was rounding and
386af8e7fd7Sriastradh 			 * whether the function is supposed to raise
387af8e7fd7Sriastradh 			 * exceptions.
388af8e7fd7Sriastradh 			 */
389af8e7fd7Sriastradh 			if (expect_except) {
390af8e7fd7Sriastradh 				ATF_CHECK_MSG(fetestexcept(FE_INEXACT) != 0,
391af8e7fd7Sriastradh 				    "[%u] %s %s(%Lf)"
392af8e7fd7Sriastradh 				    " failed to raise FE_INEXACT",
393af8e7fd7Sriastradh 				    i, rmname(valuesl[i].round_mode),
394af8e7fd7Sriastradh 				    fnname[fn], valuesl[i].input);
395af8e7fd7Sriastradh 			} else {
396af8e7fd7Sriastradh 				ATF_CHECK_MSG(fetestexcept(FE_INEXACT) == 0,
397af8e7fd7Sriastradh 				    "[%u] %s %s(%Lf)"
398af8e7fd7Sriastradh 				    " spuriously raised FE_INEXACT",
399af8e7fd7Sriastradh 				    i, rmname(valuesl[i].round_mode),
400af8e7fd7Sriastradh 				    fnname[fn], valuesl[i].input);
401af8e7fd7Sriastradh 			}
402af8e7fd7Sriastradh 
403af8e7fd7Sriastradh 			/*
404af8e7fd7Sriastradh 			 * Verify the fractional part of the result is
405af8e7fd7Sriastradh 			 * zero -- the result of rounding to an integer
406af8e7fd7Sriastradh 			 * is supposed to be an integer.
407af8e7fd7Sriastradh 			 */
408247fbbb1Sriastradh 			fpart = modfl(received, &ipart);
409247fbbb1Sriastradh 			ATF_CHECK_MSG(fpart == 0,
410af8e7fd7Sriastradh 			    "[%u] %s %s(%Lf)=%Lf has fractional part %Lf"
4112bd651d9Sriastradh 			    " (integer part %Lf)",
412af8e7fd7Sriastradh 			    i, rmname(valuesl[i].round_mode), fnname[fn],
413af8e7fd7Sriastradh 			    valuesl[i].input, received, fpart, ipart);
414af8e7fd7Sriastradh 
415af8e7fd7Sriastradh 			/*
416af8e7fd7Sriastradh 			 * Assuming the result we got has zero
417af8e7fd7Sriastradh 			 * fractional part, casting to int64_t should
418af8e7fd7Sriastradh 			 * have no rounding.  Verify it matches the
419af8e7fd7Sriastradh 			 * integer we expect.
420af8e7fd7Sriastradh 			 */
421af8e7fd7Sriastradh 			ATF_CHECK_MSG(((int64_t)received ==
422af8e7fd7Sriastradh 				valuesl[i].expected),
423af8e7fd7Sriastradh 			    "[%u] %s %s(%Lf): got %Lf, expected %jd",
424af8e7fd7Sriastradh 			    i, rmname(valuesl[i].round_mode), fnname[fn],
425247fbbb1Sriastradh 			    valuesl[i].input, received, valuesl[i].expected);
426247fbbb1Sriastradh 
427247fbbb1Sriastradh 			/* Do we get the same rounding mode out? */
428247fbbb1Sriastradh 			ATF_CHECK_MSG(fegetround() == valuesl[i].round_mode,
429af8e7fd7Sriastradh 			    "[%u] %s: set %d (%s), got %d (%s)",
430af8e7fd7Sriastradh 			    i, fnname[fn],
431af8e7fd7Sriastradh 			    valuesl[i].round_mode,
432af8e7fd7Sriastradh 			    rmname(valuesl[i].round_mode),
433247fbbb1Sriastradh 			    fegetround(), rmname(fegetround()));
434247fbbb1Sriastradh 		}
435247fbbb1Sriastradh 	}
436af8e7fd7Sriastradh }
437247fbbb1Sriastradh 
43820b05e74Sriastradh #endif	/* __HAVE_LONG_DOUBLE */
4397a813f9eShe 
ATF_TP_ADD_TCS(tp)440377c57d5Smaya ATF_TP_ADD_TCS(tp)
441377c57d5Smaya {
442377c57d5Smaya 
443af8e7fd7Sriastradh 	ATF_TP_ADD_TC(tp, fe_lrint);
444af8e7fd7Sriastradh 	ATF_TP_ADD_TC(tp, fe_nearbyint_rint);
445247fbbb1Sriastradh #ifdef __HAVE_LONG_DOUBLE
446af8e7fd7Sriastradh 	ATF_TP_ADD_TC(tp, fe_nearbyintl_rintl);
447247fbbb1Sriastradh #endif
448377c57d5Smaya 
449377c57d5Smaya 	return atf_no_error();
450377c57d5Smaya }
451377c57d5Smaya 
45220b05e74Sriastradh #else  /* !__HAVE_FENV */
45386dc433aShe 
ATF_TP_ADD_TCS(tp)454377c57d5Smaya ATF_TP_ADD_TCS(tp)
455377c57d5Smaya {
45620b05e74Sriastradh 
45720b05e74Sriastradh 	/*
45820b05e74Sriastradh 	 * No fenv, no fesetround to test.
45920b05e74Sriastradh 	 */
460377c57d5Smaya 	return atf_no_error();
461377c57d5Smaya }
462377c57d5Smaya 
46320b05e74Sriastradh #endif	/* __HAVE_FENV */
464