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