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