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