t_fe_round.c revision 1.12 1 1.1 maya /*
2 1.1 maya * Written by Maya Rashish <maya (at) NetBSD.org>
3 1.1 maya * Public domain.
4 1.1 maya *
5 1.1 maya * Testing IEEE-754 rounding modes (and lrint)
6 1.1 maya */
7 1.1 maya
8 1.1 maya #include <atf-c.h>
9 1.1 maya #include <fenv.h>
10 1.1 maya #ifdef __HAVE_FENV
11 1.1 maya #include <math.h>
12 1.12 kre #include <stdint.h>
13 1.1 maya #include <stdio.h>
14 1.1 maya #include <stdlib.h>
15 1.1 maya
16 1.1 maya /*#pragma STDC FENV_ACCESS ON gcc?? */
17 1.1 maya
18 1.1 maya #define INT 9223L
19 1.1 maya
20 1.1 maya #define EPSILON 0.001
21 1.1 maya
22 1.10 riastrad static const char *
23 1.10 riastrad rmname(int rm)
24 1.10 riastrad {
25 1.10 riastrad switch (rm) {
26 1.10 riastrad case FE_TOWARDZERO:
27 1.10 riastrad return "FE_TOWARDZERO";
28 1.10 riastrad case FE_DOWNWARD:
29 1.10 riastrad return "FE_DOWNWARD";
30 1.10 riastrad case FE_UPWARD:
31 1.10 riastrad return "FE_UPWARD";
32 1.10 riastrad case FE_TONEAREST:
33 1.10 riastrad return "FE_TONEAREST";
34 1.10 riastrad default:
35 1.10 riastrad return "unknown";
36 1.10 riastrad }
37 1.10 riastrad }
38 1.10 riastrad
39 1.1 maya static const struct {
40 1.1 maya int round_mode;
41 1.1 maya double input;
42 1.1 maya long int expected;
43 1.1 maya } values[] = {
44 1.1 maya { FE_DOWNWARD, 3.7, 3},
45 1.1 maya { FE_DOWNWARD, -3.7, -4},
46 1.1 maya { FE_DOWNWARD, +0, 0},
47 1.1 maya { FE_DOWNWARD, -INT-0.01, -INT-1},
48 1.1 maya { FE_DOWNWARD, +INT-0.01, INT-1},
49 1.1 maya { FE_DOWNWARD, -INT+0.01, -INT},
50 1.1 maya { FE_DOWNWARD, +INT+0.01, INT},
51 1.1 maya #if 0 /* cpu bugs? */
52 1.1 maya { FE_DOWNWARD, -0, -1},
53 1.1 maya
54 1.1 maya { FE_UPWARD, +0, 1},
55 1.1 maya #endif
56 1.1 maya { FE_UPWARD, -0, 0},
57 1.1 maya { FE_UPWARD, -123.7, -123},
58 1.1 maya { FE_UPWARD, 123.999, 124},
59 1.1 maya { FE_UPWARD, -INT-0.01, -INT},
60 1.1 maya { FE_UPWARD, +INT-0.01, INT},
61 1.1 maya { FE_UPWARD, -INT+0.01, -INT+1},
62 1.1 maya { FE_UPWARD, +INT+0.01, INT+1},
63 1.1 maya
64 1.1 maya { FE_TOWARDZERO, 1.99, 1},
65 1.1 maya { FE_TOWARDZERO, -1.99, -1},
66 1.1 maya { FE_TOWARDZERO, 0.2, 0},
67 1.1 maya { FE_TOWARDZERO, INT+0.01, INT},
68 1.1 maya { FE_TOWARDZERO, INT-0.01, INT - 1},
69 1.1 maya { FE_TOWARDZERO, -INT+0.01, -INT + 1},
70 1.1 maya { FE_TOWARDZERO, +0, 0},
71 1.1 maya { FE_TOWARDZERO, -0, 0},
72 1.1 maya
73 1.1 maya { FE_TONEAREST, -INT-0.01, -INT},
74 1.1 maya { FE_TONEAREST, +INT-0.01, INT},
75 1.1 maya { FE_TONEAREST, -INT+0.01, -INT},
76 1.1 maya { FE_TONEAREST, +INT+0.01, INT},
77 1.1 maya { FE_TONEAREST, -INT-0.501, -INT-1},
78 1.1 maya { FE_TONEAREST, +INT-0.501, INT-1},
79 1.1 maya { FE_TONEAREST, -INT+0.501, -INT+1},
80 1.1 maya { FE_TONEAREST, +INT+0.501, INT+1},
81 1.1 maya { FE_TONEAREST, +0, 0},
82 1.1 maya { FE_TONEAREST, -0, 0},
83 1.1 maya };
84 1.1 maya
85 1.1 maya ATF_TC(fe_round);
86 1.1 maya ATF_TC_HEAD(fe_round, tc)
87 1.1 maya {
88 1.1 maya atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using lrint");
89 1.1 maya }
90 1.1 maya
91 1.1 maya ATF_TC_BODY(fe_round, tc)
92 1.1 maya {
93 1.1 maya long int received;
94 1.1 maya
95 1.1 maya for (unsigned int i = 0; i < __arraycount(values); i++) {
96 1.1 maya fesetround(values[i].round_mode);
97 1.1 maya
98 1.1 maya received = lrint(values[i].input);
99 1.1 maya ATF_CHECK_MSG(
100 1.2 maya (labs(received - values[i].expected) < EPSILON),
101 1.1 maya "lrint rounding wrong, difference too large\n"
102 1.1 maya "input: %f (index %d): got %ld, expected %ld\n",
103 1.1 maya values[i].input, i, received, values[i].expected);
104 1.1 maya
105 1.1 maya /* Do we get the same rounding mode out? */
106 1.1 maya ATF_CHECK_MSG(
107 1.1 maya (fegetround() == values[i].round_mode),
108 1.1 maya "Didn't get the same rounding mode out!\n"
109 1.1 maya "(index %d) fed in %d rounding mode, got %d out\n",
110 1.3 he i, values[i].round_mode, fegetround());
111 1.1 maya }
112 1.1 maya }
113 1.1 maya
114 1.6 he ATF_TC(fe_nearbyint);
115 1.6 he ATF_TC_HEAD(fe_nearbyint, tc)
116 1.6 he {
117 1.10 riastrad atf_tc_set_md_var(tc, "descr",
118 1.10 riastrad "Checking IEEE 754 rounding modes using nearbyint");
119 1.6 he }
120 1.6 he
121 1.6 he ATF_TC_BODY(fe_nearbyint, tc)
122 1.6 he {
123 1.10 riastrad double received, ipart, fpart;
124 1.6 he
125 1.6 he for (unsigned int i = 0; i < __arraycount(values); i++) {
126 1.6 he fesetround(values[i].round_mode);
127 1.6 he
128 1.6 he received = nearbyint(values[i].input);
129 1.10 riastrad fpart = modf(received, &ipart);
130 1.10 riastrad ATF_CHECK_MSG(fpart == 0,
131 1.10 riastrad "%s nearbyint(%f) has fractional part %f",
132 1.10 riastrad rmname(values[i].round_mode), values[i].input, fpart);
133 1.10 riastrad ATF_CHECK_MSG((long int)received == values[i].expected,
134 1.10 riastrad "%s [%u] nearbyint(%f) got %f, expected %ld\n",
135 1.10 riastrad rmname(values[i].round_mode),
136 1.10 riastrad i, values[i].input, received, values[i].expected);
137 1.6 he
138 1.6 he /* Do we get the same rounding mode out? */
139 1.10 riastrad ATF_CHECK_MSG(fegetround() == values[i].round_mode,
140 1.10 riastrad "[%u] set %d (%s), got %d (%s)",
141 1.10 riastrad i,
142 1.10 riastrad values[i].round_mode, rmname(values[i].round_mode),
143 1.10 riastrad fegetround(), rmname(fegetround()));
144 1.6 he }
145 1.6 he }
146 1.6 he
147 1.11 riastrad #ifdef __HAVE_LONG_DOUBLE
148 1.11 riastrad
149 1.12 kre #define IM intmax_t
150 1.12 kre
151 1.11 riastrad /*
152 1.11 riastrad * Use one bit more than fits in IEEE 754 binary64.
153 1.11 riastrad */
154 1.11 riastrad static const struct {
155 1.11 riastrad int round_mode;
156 1.11 riastrad long double input;
157 1.12 kre IM expected;
158 1.11 riastrad } valuesl[] = {
159 1.12 kre { FE_TOWARDZERO, 0x2.00000000000008p+52L, (IM)0x20000000000000 },
160 1.12 kre { FE_DOWNWARD, 0x2.00000000000008p+52L, (IM)0x20000000000000 },
161 1.12 kre { FE_UPWARD, 0x2.00000000000008p+52L, (IM)0x20000000000001 },
162 1.12 kre { FE_TONEAREST, 0x2.00000000000008p+52L, (IM)0x20000000000000 },
163 1.12 kre { FE_TOWARDZERO, 0x2.00000000000018p+52L, (IM)0x20000000000001 },
164 1.12 kre { FE_DOWNWARD, 0x2.00000000000018p+52L, (IM)0x20000000000001 },
165 1.12 kre { FE_UPWARD, 0x2.00000000000018p+52L, (IM)0x20000000000002 },
166 1.12 kre { FE_TONEAREST, 0x2.00000000000018p+52L, (IM)0x20000000000002 },
167 1.11 riastrad };
168 1.11 riastrad
169 1.12 kre #undef IM
170 1.12 kre
171 1.11 riastrad ATF_TC(fe_nearbyintl);
172 1.11 riastrad ATF_TC_HEAD(fe_nearbyintl, tc)
173 1.11 riastrad {
174 1.11 riastrad atf_tc_set_md_var(tc, "descr",
175 1.11 riastrad "Checking IEEE 754 rounding modes using nearbyintl");
176 1.11 riastrad }
177 1.11 riastrad
178 1.11 riastrad ATF_TC_BODY(fe_nearbyintl, tc)
179 1.11 riastrad {
180 1.11 riastrad long double received, ipart, fpart;
181 1.11 riastrad
182 1.11 riastrad for (unsigned int i = 0; i < __arraycount(valuesl); i++) {
183 1.11 riastrad fesetround(valuesl[i].round_mode);
184 1.11 riastrad
185 1.11 riastrad received = nearbyintl(valuesl[i].input);
186 1.11 riastrad fpart = modfl(received, &ipart);
187 1.11 riastrad ATF_CHECK_MSG(fpart == 0,
188 1.11 riastrad "%s nearbyintl(%Lf) has fractional part %Lf",
189 1.11 riastrad rmname(values[i].round_mode), valuesl[i].input, fpart);
190 1.11 riastrad ATF_CHECK_MSG((long int)received == valuesl[i].expected,
191 1.12 kre "%s [%u] nearbyint(%Lf): got %Lf, expected %jd",
192 1.11 riastrad rmname(values[i].round_mode), i,
193 1.11 riastrad valuesl[i].input, received, valuesl[i].expected);
194 1.11 riastrad
195 1.11 riastrad /* Do we get the same rounding mode out? */
196 1.11 riastrad ATF_CHECK_MSG(fegetround() == valuesl[i].round_mode,
197 1.11 riastrad "[%u] set %d (%s), got %d (%s)",
198 1.11 riastrad i,
199 1.11 riastrad valuesl[i].round_mode, rmname(valuesl[i].round_mode),
200 1.11 riastrad fegetround(), rmname(fegetround()));
201 1.11 riastrad }
202 1.11 riastrad }
203 1.11 riastrad
204 1.11 riastrad #endif
205 1.11 riastrad
206 1.7 he static const struct {
207 1.7 he double input;
208 1.7 he double toward;
209 1.7 he double expected;
210 1.7 he } values2[] = {
211 1.7 he { 10.0, 11.0, 10.0 },
212 1.7 he { -5.0, -6.0, -5.0 },
213 1.7 he };
214 1.7 he
215 1.7 he ATF_TC(fe_nextafter);
216 1.7 he ATF_TC_HEAD(fe_nextafter, tc)
217 1.7 he {
218 1.7 he atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nextafter()");
219 1.7 he }
220 1.7 he
221 1.7 he ATF_TC_BODY(fe_nextafter, tc)
222 1.7 he {
223 1.7 he double received;
224 1.7 he int res;
225 1.7 he
226 1.7 he for (unsigned int i = 0; i < __arraycount(values2); i++) {
227 1.7 he received = nextafter(values2[i].input, values2[i].toward);
228 1.7 he if (values2[i].input < values2[i].toward) {
229 1.7 he res = (received > values2[i].input);
230 1.7 he } else {
231 1.7 he res = (received < values2[i].input);
232 1.7 he }
233 1.7 he ATF_CHECK_MSG(
234 1.7 he res && (fabs(received - values2[i].expected) < EPSILON),
235 1.7 he "nextafter() rounding wrong, difference too large\n"
236 1.7 he "input: %f (index %d): got %f, expected %f, res %d\n",
237 1.7 he values2[i].input, i, received, values2[i].expected, res);
238 1.7 he }
239 1.7 he }
240 1.7 he
241 1.7 he ATF_TC(fe_nexttoward);
242 1.7 he ATF_TC_HEAD(fe_nexttoward, tc)
243 1.7 he {
244 1.7 he atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nexttoward()");
245 1.7 he }
246 1.7 he
247 1.7 he ATF_TC_BODY(fe_nexttoward, tc)
248 1.7 he {
249 1.7 he double received;
250 1.7 he int res;
251 1.7 he
252 1.7 he for (unsigned int i = 0; i < __arraycount(values2); i++) {
253 1.7 he received = nexttoward(values2[i].input, values2[i].toward);
254 1.7 he if (values2[i].input < values2[i].toward) {
255 1.7 he res = (received > values2[i].input);
256 1.7 he } else {
257 1.7 he res = (received < values2[i].input);
258 1.7 he }
259 1.7 he ATF_CHECK_MSG(
260 1.7 he res && (fabs(received - values2[i].expected) < EPSILON),
261 1.7 he "nexttoward() rounding wrong, difference too large\n"
262 1.7 he "input: %f (index %d): got %f, expected %f, res %d\n",
263 1.7 he values2[i].input, i, received, values2[i].expected, res);
264 1.7 he }
265 1.7 he }
266 1.7 he
267 1.1 maya ATF_TP_ADD_TCS(tp)
268 1.1 maya {
269 1.1 maya
270 1.1 maya ATF_TP_ADD_TC(tp, fe_round);
271 1.6 he ATF_TP_ADD_TC(tp, fe_nearbyint);
272 1.11 riastrad #ifdef __HAVE_LONG_DOUBLE
273 1.11 riastrad ATF_TP_ADD_TC(tp, fe_nearbyintl);
274 1.11 riastrad #endif
275 1.7 he ATF_TP_ADD_TC(tp, fe_nextafter);
276 1.7 he ATF_TP_ADD_TC(tp, fe_nexttoward);
277 1.1 maya
278 1.1 maya return atf_no_error();
279 1.1 maya }
280 1.1 maya #else
281 1.1 maya ATF_TC(t_nofe_round);
282 1.1 maya
283 1.1 maya ATF_TC_HEAD(t_nofe_round, tc)
284 1.1 maya {
285 1.1 maya atf_tc_set_md_var(tc, "descr",
286 1.1 maya "dummy test case - no fenv.h support");
287 1.1 maya }
288 1.1 maya
289 1.4 he ATF_TC_BODY(t_nofe_round, tc)
290 1.4 he {
291 1.4 he atf_tc_skip("no fenv.h support on this architecture");
292 1.4 he }
293 1.1 maya
294 1.6 he ATF_TC(t_nofe_nearbyint);
295 1.6 he
296 1.6 he ATF_TC_HEAD(t_nofe_nearbyint, tc)
297 1.6 he {
298 1.6 he atf_tc_set_md_var(tc, "descr",
299 1.6 he "dummy test case - no fenv.h support");
300 1.6 he }
301 1.6 he
302 1.6 he ATF_TC_BODY(t_nofe_nearbyint, tc)
303 1.6 he {
304 1.6 he atf_tc_skip("no fenv.h support on this architecture");
305 1.6 he }
306 1.6 he
307 1.7 he ATF_TC(t_nofe_nextafter);
308 1.7 he
309 1.7 he ATF_TC_HEAD(t_nofe_nextafter, tc)
310 1.7 he {
311 1.7 he atf_tc_set_md_var(tc, "descr",
312 1.7 he "dummy test case - no fenv.h support");
313 1.7 he }
314 1.7 he
315 1.7 he ATF_TC_BODY(t_nofe_nextafter, tc)
316 1.7 he {
317 1.7 he atf_tc_skip("no fenv.h support on this architecture");
318 1.7 he }
319 1.7 he
320 1.7 he ATF_TC(t_nofe_nexttoward);
321 1.7 he
322 1.7 he ATF_TC_HEAD(t_nofe_nexttoward, tc)
323 1.7 he {
324 1.7 he atf_tc_set_md_var(tc, "descr",
325 1.7 he "dummy test case - no fenv.h support");
326 1.7 he }
327 1.7 he
328 1.7 he ATF_TC_BODY(t_nofe_nexttoward, tc)
329 1.7 he {
330 1.7 he atf_tc_skip("no fenv.h support on this architecture");
331 1.7 he }
332 1.6 he
333 1.1 maya ATF_TP_ADD_TCS(tp)
334 1.1 maya {
335 1.1 maya ATF_TP_ADD_TC(tp, t_nofe_round);
336 1.6 he ATF_TP_ADD_TC(tp, t_nofe_nearbyint);
337 1.7 he ATF_TP_ADD_TC(tp, t_nofe_nextafter);
338 1.7 he ATF_TP_ADD_TC(tp, t_nofe_nexttoward);
339 1.1 maya return atf_no_error();
340 1.1 maya }
341 1.1 maya
342 1.1 maya #endif
343