xref: /freebsd/contrib/netbsd-tests/lib/libm/t_fe_round.c (revision 1ec3feb64826d2a43d41e74684690985bf20e71c)
1cdebaff8SEnji Cooper /*
2cdebaff8SEnji Cooper  * Written by Maya Rashish <maya@NetBSD.org>
3cdebaff8SEnji Cooper  * Public domain.
4cdebaff8SEnji Cooper  *
5cdebaff8SEnji Cooper  * Testing IEEE-754 rounding modes (and lrint)
6cdebaff8SEnji Cooper  */
7cdebaff8SEnji Cooper 
8cdebaff8SEnji Cooper #include <atf-c.h>
9cdebaff8SEnji Cooper #include <fenv.h>
10cdebaff8SEnji Cooper #ifdef __HAVE_FENV
11cdebaff8SEnji Cooper #include <math.h>
12cdebaff8SEnji Cooper #include <stdio.h>
13cdebaff8SEnji Cooper #include <stdlib.h>
14cdebaff8SEnji Cooper 
15cdebaff8SEnji Cooper /*#pragma STDC FENV_ACCESS ON gcc?? */
16cdebaff8SEnji Cooper 
17cdebaff8SEnji Cooper #define INT 9223L
18cdebaff8SEnji Cooper 
19cdebaff8SEnji Cooper #define EPSILON 0.001
20cdebaff8SEnji Cooper 
21cdebaff8SEnji Cooper static const struct {
22cdebaff8SEnji Cooper 	int round_mode;
23cdebaff8SEnji Cooper 	double input;
24cdebaff8SEnji Cooper 	long int expected;
25cdebaff8SEnji Cooper } values[] = {
26cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		3.7,		3},
27cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		-3.7,		-4},
28cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		+0,		0},
29cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		-INT-0.01,	-INT-1},
30cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		+INT-0.01,	INT-1},
31cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		-INT+0.01,	-INT},
32cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		+INT+0.01,	INT},
33cdebaff8SEnji Cooper #if 0 /* cpu bugs? */
34cdebaff8SEnji Cooper 	{ FE_DOWNWARD,		-0,		-1},
35cdebaff8SEnji Cooper 
36cdebaff8SEnji Cooper 	{ FE_UPWARD,		+0,		1},
37cdebaff8SEnji Cooper #endif
38cdebaff8SEnji Cooper 	{ FE_UPWARD,		-0,		0},
39cdebaff8SEnji Cooper 	{ FE_UPWARD,		-123.7,		-123},
40cdebaff8SEnji Cooper 	{ FE_UPWARD,		123.999,	124},
41cdebaff8SEnji Cooper 	{ FE_UPWARD,		-INT-0.01,	-INT},
42cdebaff8SEnji Cooper 	{ FE_UPWARD,		+INT-0.01,	INT},
43cdebaff8SEnji Cooper 	{ FE_UPWARD,		-INT+0.01,	-INT+1},
44cdebaff8SEnji Cooper 	{ FE_UPWARD,		+INT+0.01,	INT+1},
45cdebaff8SEnji Cooper 
46cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	1.99,		1},
47cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	-1.99,		-1},
48cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	0.2,		0},
49cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	INT+0.01,	INT},
50cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	INT-0.01,	INT - 1},
51cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	-INT+0.01,	-INT + 1},
52cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	+0,		0},
53cdebaff8SEnji Cooper 	{ FE_TOWARDZERO,	-0,		0},
54cdebaff8SEnji Cooper 
55cdebaff8SEnji Cooper 	{ FE_TONEAREST,		-INT-0.01,	-INT},
56cdebaff8SEnji Cooper 	{ FE_TONEAREST,		+INT-0.01,	INT},
57cdebaff8SEnji Cooper 	{ FE_TONEAREST,		-INT+0.01,	-INT},
58cdebaff8SEnji Cooper 	{ FE_TONEAREST,		+INT+0.01,	INT},
59cdebaff8SEnji Cooper 	{ FE_TONEAREST,		-INT-0.501,	-INT-1},
60cdebaff8SEnji Cooper 	{ FE_TONEAREST,		+INT-0.501,	INT-1},
61cdebaff8SEnji Cooper 	{ FE_TONEAREST,		-INT+0.501,	-INT+1},
62cdebaff8SEnji Cooper 	{ FE_TONEAREST,		+INT+0.501,	INT+1},
63cdebaff8SEnji Cooper 	{ FE_TONEAREST,		+0,		0},
64cdebaff8SEnji Cooper 	{ FE_TONEAREST,		-0,		0},
65cdebaff8SEnji Cooper };
66cdebaff8SEnji Cooper 
67cdebaff8SEnji Cooper ATF_TC(fe_round);
ATF_TC_HEAD(fe_round,tc)68cdebaff8SEnji Cooper ATF_TC_HEAD(fe_round, tc)
69cdebaff8SEnji Cooper {
70cdebaff8SEnji Cooper 	atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using lrint");
71cdebaff8SEnji Cooper }
72cdebaff8SEnji Cooper 
ATF_TC_BODY(fe_round,tc)73cdebaff8SEnji Cooper ATF_TC_BODY(fe_round, tc)
74cdebaff8SEnji Cooper {
75cdebaff8SEnji Cooper 	long int received;
76cdebaff8SEnji Cooper 
77cdebaff8SEnji Cooper 	for (unsigned int i = 0; i < __arraycount(values); i++) {
78cdebaff8SEnji Cooper 		fesetround(values[i].round_mode);
79cdebaff8SEnji Cooper 
80cdebaff8SEnji Cooper 		received = lrint(values[i].input);
81cdebaff8SEnji Cooper 		ATF_CHECK_MSG(
82cdebaff8SEnji Cooper 		    (labs(received - values[i].expected) < EPSILON),
83cdebaff8SEnji Cooper 		    "lrint rounding wrong, difference too large\n"
84cdebaff8SEnji Cooper 		    "input: %f (index %d): got %ld, expected %ld\n",
85cdebaff8SEnji Cooper 		    values[i].input, i, received, values[i].expected);
86cdebaff8SEnji Cooper 
87cdebaff8SEnji Cooper 		/* Do we get the same rounding mode out? */
88cdebaff8SEnji Cooper 		ATF_CHECK_MSG(
89cdebaff8SEnji Cooper 		    (fegetround() == values[i].round_mode),
90cdebaff8SEnji Cooper 		    "Didn't get the same rounding mode out!\n"
91cdebaff8SEnji Cooper 		    "(index %d) fed in %d rounding mode, got %d out\n",
92*1ec3feb6SAlex Richardson 		    i, values[i].round_mode, fegetround());
93*1ec3feb6SAlex Richardson 	}
94*1ec3feb6SAlex Richardson }
95*1ec3feb6SAlex Richardson 
96*1ec3feb6SAlex Richardson ATF_TC(fe_nearbyint);
ATF_TC_HEAD(fe_nearbyint,tc)97*1ec3feb6SAlex Richardson ATF_TC_HEAD(fe_nearbyint, tc)
98*1ec3feb6SAlex Richardson {
99*1ec3feb6SAlex Richardson 	atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using nearbyint");
100*1ec3feb6SAlex Richardson }
101*1ec3feb6SAlex Richardson 
ATF_TC_BODY(fe_nearbyint,tc)102*1ec3feb6SAlex Richardson ATF_TC_BODY(fe_nearbyint, tc)
103*1ec3feb6SAlex Richardson {
104*1ec3feb6SAlex Richardson 	double received;
105*1ec3feb6SAlex Richardson 
106*1ec3feb6SAlex Richardson 	for (unsigned int i = 0; i < __arraycount(values); i++) {
107*1ec3feb6SAlex Richardson 		fesetround(values[i].round_mode);
108*1ec3feb6SAlex Richardson 
109*1ec3feb6SAlex Richardson 		received = nearbyint(values[i].input);
110*1ec3feb6SAlex Richardson 		ATF_CHECK_MSG(
111*1ec3feb6SAlex Richardson 		    (fabs(received - values[i].expected) < EPSILON),
112*1ec3feb6SAlex Richardson 		    "nearbyint rounding wrong, difference too large\n"
113*1ec3feb6SAlex Richardson 		    "input: %f (index %d): got %f, expected %ld\n",
114*1ec3feb6SAlex Richardson 		    values[i].input, i, received, values[i].expected);
115*1ec3feb6SAlex Richardson 
116*1ec3feb6SAlex Richardson 		/* Do we get the same rounding mode out? */
117*1ec3feb6SAlex Richardson 		ATF_CHECK_MSG(
118*1ec3feb6SAlex Richardson 		    (fegetround() == values[i].round_mode),
119*1ec3feb6SAlex Richardson 		    "Didn't get the same rounding mode out!\n"
120*1ec3feb6SAlex Richardson 		    "(index %d) fed in %d rounding mode, got %d out\n",
121*1ec3feb6SAlex Richardson 		    i, values[i].round_mode, fegetround());
122*1ec3feb6SAlex Richardson 	}
123*1ec3feb6SAlex Richardson }
124*1ec3feb6SAlex Richardson 
125*1ec3feb6SAlex Richardson static const struct {
126*1ec3feb6SAlex Richardson 	double input;
127*1ec3feb6SAlex Richardson 	double toward;
128*1ec3feb6SAlex Richardson 	double expected;
129*1ec3feb6SAlex Richardson } values2[] = {
130*1ec3feb6SAlex Richardson 	{ 10.0, 11.0, 10.0 },
131*1ec3feb6SAlex Richardson 	{ -5.0, -6.0, -5.0 },
132*1ec3feb6SAlex Richardson };
133*1ec3feb6SAlex Richardson 
134*1ec3feb6SAlex Richardson ATF_TC(fe_nextafter);
ATF_TC_HEAD(fe_nextafter,tc)135*1ec3feb6SAlex Richardson ATF_TC_HEAD(fe_nextafter, tc)
136*1ec3feb6SAlex Richardson {
137*1ec3feb6SAlex Richardson 	atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nextafter()");
138*1ec3feb6SAlex Richardson }
139*1ec3feb6SAlex Richardson 
ATF_TC_BODY(fe_nextafter,tc)140*1ec3feb6SAlex Richardson ATF_TC_BODY(fe_nextafter, tc)
141*1ec3feb6SAlex Richardson {
142*1ec3feb6SAlex Richardson 	double received;
143*1ec3feb6SAlex Richardson 	int res;
144*1ec3feb6SAlex Richardson 
145*1ec3feb6SAlex Richardson 	for (unsigned int i = 0; i < __arraycount(values2); i++) {
146*1ec3feb6SAlex Richardson 		received = nextafter(values2[i].input, values2[i].toward);
147*1ec3feb6SAlex Richardson 		if (values2[i].input < values2[i].toward) {
148*1ec3feb6SAlex Richardson 			res = (received > values2[i].input);
149*1ec3feb6SAlex Richardson 		} else {
150*1ec3feb6SAlex Richardson 			res = (received < values2[i].input);
151*1ec3feb6SAlex Richardson 		}
152*1ec3feb6SAlex Richardson 		ATF_CHECK_MSG(
153*1ec3feb6SAlex Richardson 			res && (fabs(received - values2[i].expected) < EPSILON),
154*1ec3feb6SAlex Richardson 			"nextafter() rounding wrong, difference too large\n"
155*1ec3feb6SAlex Richardson 			"input: %f (index %d): got %f, expected %f, res %d\n",
156*1ec3feb6SAlex Richardson 			values2[i].input, i, received, values2[i].expected, res);
157*1ec3feb6SAlex Richardson 	}
158*1ec3feb6SAlex Richardson }
159*1ec3feb6SAlex Richardson 
160*1ec3feb6SAlex Richardson ATF_TC(fe_nexttoward);
ATF_TC_HEAD(fe_nexttoward,tc)161*1ec3feb6SAlex Richardson ATF_TC_HEAD(fe_nexttoward, tc)
162*1ec3feb6SAlex Richardson {
163*1ec3feb6SAlex Richardson 	atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nexttoward()");
164*1ec3feb6SAlex Richardson }
165*1ec3feb6SAlex Richardson 
ATF_TC_BODY(fe_nexttoward,tc)166*1ec3feb6SAlex Richardson ATF_TC_BODY(fe_nexttoward, tc)
167*1ec3feb6SAlex Richardson {
168*1ec3feb6SAlex Richardson 	double received;
169*1ec3feb6SAlex Richardson 	int res;
170*1ec3feb6SAlex Richardson 
171*1ec3feb6SAlex Richardson 	for (unsigned int i = 0; i < __arraycount(values2); i++) {
172*1ec3feb6SAlex Richardson 		received = nexttoward(values2[i].input, values2[i].toward);
173*1ec3feb6SAlex Richardson 		if (values2[i].input < values2[i].toward) {
174*1ec3feb6SAlex Richardson 			res = (received > values2[i].input);
175*1ec3feb6SAlex Richardson 		} else {
176*1ec3feb6SAlex Richardson 			res = (received < values2[i].input);
177*1ec3feb6SAlex Richardson 		}
178*1ec3feb6SAlex Richardson 		ATF_CHECK_MSG(
179*1ec3feb6SAlex Richardson 			res && (fabs(received - values2[i].expected) < EPSILON),
180*1ec3feb6SAlex Richardson 			"nexttoward() rounding wrong, difference too large\n"
181*1ec3feb6SAlex Richardson 			"input: %f (index %d): got %f, expected %f, res %d\n",
182*1ec3feb6SAlex Richardson 			values2[i].input, i, received, values2[i].expected, res);
183cdebaff8SEnji Cooper 	}
184cdebaff8SEnji Cooper }
185cdebaff8SEnji Cooper 
ATF_TP_ADD_TCS(tp)186cdebaff8SEnji Cooper ATF_TP_ADD_TCS(tp)
187cdebaff8SEnji Cooper {
188cdebaff8SEnji Cooper 
189cdebaff8SEnji Cooper 	ATF_TP_ADD_TC(tp, fe_round);
190*1ec3feb6SAlex Richardson 	ATF_TP_ADD_TC(tp, fe_nearbyint);
191*1ec3feb6SAlex Richardson 	ATF_TP_ADD_TC(tp, fe_nextafter);
192*1ec3feb6SAlex Richardson 	ATF_TP_ADD_TC(tp, fe_nexttoward);
193cdebaff8SEnji Cooper 
194cdebaff8SEnji Cooper 	return atf_no_error();
195cdebaff8SEnji Cooper }
196cdebaff8SEnji Cooper #else
197cdebaff8SEnji Cooper ATF_TC(t_nofe_round);
198cdebaff8SEnji Cooper 
ATF_TC_HEAD(t_nofe_round,tc)199cdebaff8SEnji Cooper ATF_TC_HEAD(t_nofe_round, tc)
200cdebaff8SEnji Cooper {
201cdebaff8SEnji Cooper 	atf_tc_set_md_var(tc, "descr",
202cdebaff8SEnji Cooper 	    "dummy test case - no fenv.h support");
203cdebaff8SEnji Cooper }
204cdebaff8SEnji Cooper 
ATF_TC_BODY(t_nofe_round,tc)205cdebaff8SEnji Cooper ATF_TC_BODY(t_nofe_round, tc)
206cdebaff8SEnji Cooper {
207cdebaff8SEnji Cooper 	atf_tc_skip("no fenv.h support on this architecture");
208cdebaff8SEnji Cooper }
209cdebaff8SEnji Cooper 
210*1ec3feb6SAlex Richardson ATF_TC(t_nofe_nearbyint);
211*1ec3feb6SAlex Richardson 
ATF_TC_HEAD(t_nofe_nearbyint,tc)212*1ec3feb6SAlex Richardson ATF_TC_HEAD(t_nofe_nearbyint, tc)
213*1ec3feb6SAlex Richardson {
214*1ec3feb6SAlex Richardson 	atf_tc_set_md_var(tc, "descr",
215*1ec3feb6SAlex Richardson 	    "dummy test case - no fenv.h support");
216*1ec3feb6SAlex Richardson }
217*1ec3feb6SAlex Richardson 
ATF_TC_BODY(t_nofe_nearbyint,tc)218*1ec3feb6SAlex Richardson ATF_TC_BODY(t_nofe_nearbyint, tc)
219*1ec3feb6SAlex Richardson {
220*1ec3feb6SAlex Richardson 	atf_tc_skip("no fenv.h support on this architecture");
221*1ec3feb6SAlex Richardson }
222*1ec3feb6SAlex Richardson 
223*1ec3feb6SAlex Richardson ATF_TC(t_nofe_nextafter);
224*1ec3feb6SAlex Richardson 
ATF_TC_HEAD(t_nofe_nextafter,tc)225*1ec3feb6SAlex Richardson ATF_TC_HEAD(t_nofe_nextafter, tc)
226*1ec3feb6SAlex Richardson {
227*1ec3feb6SAlex Richardson 	atf_tc_set_md_var(tc, "descr",
228*1ec3feb6SAlex Richardson 	    "dummy test case - no fenv.h support");
229*1ec3feb6SAlex Richardson }
230*1ec3feb6SAlex Richardson 
ATF_TC_BODY(t_nofe_nextafter,tc)231*1ec3feb6SAlex Richardson ATF_TC_BODY(t_nofe_nextafter, tc)
232*1ec3feb6SAlex Richardson {
233*1ec3feb6SAlex Richardson 	atf_tc_skip("no fenv.h support on this architecture");
234*1ec3feb6SAlex Richardson }
235*1ec3feb6SAlex Richardson 
236*1ec3feb6SAlex Richardson ATF_TC(t_nofe_nexttoward);
237*1ec3feb6SAlex Richardson 
ATF_TC_HEAD(t_nofe_nexttoward,tc)238*1ec3feb6SAlex Richardson ATF_TC_HEAD(t_nofe_nexttoward, tc)
239*1ec3feb6SAlex Richardson {
240*1ec3feb6SAlex Richardson 	atf_tc_set_md_var(tc, "descr",
241*1ec3feb6SAlex Richardson 	    "dummy test case - no fenv.h support");
242*1ec3feb6SAlex Richardson }
243*1ec3feb6SAlex Richardson 
ATF_TC_BODY(t_nofe_nexttoward,tc)244*1ec3feb6SAlex Richardson ATF_TC_BODY(t_nofe_nexttoward, tc)
245*1ec3feb6SAlex Richardson {
246*1ec3feb6SAlex Richardson 	atf_tc_skip("no fenv.h support on this architecture");
247*1ec3feb6SAlex Richardson }
248*1ec3feb6SAlex Richardson 
ATF_TP_ADD_TCS(tp)249cdebaff8SEnji Cooper ATF_TP_ADD_TCS(tp)
250cdebaff8SEnji Cooper {
251cdebaff8SEnji Cooper 	ATF_TP_ADD_TC(tp, t_nofe_round);
252*1ec3feb6SAlex Richardson 	ATF_TP_ADD_TC(tp, t_nofe_nearbyint);
253*1ec3feb6SAlex Richardson 	ATF_TP_ADD_TC(tp, t_nofe_nextafter);
254*1ec3feb6SAlex Richardson 	ATF_TP_ADD_TC(tp, t_nofe_nexttoward);
255cdebaff8SEnji Cooper 	return atf_no_error();
256cdebaff8SEnji Cooper }
257cdebaff8SEnji Cooper 
258cdebaff8SEnji Cooper #endif
259