]>
Commit | Line | Data |
---|---|---|
46692946 PM |
1 | /* Test for correct rounding of results of strtod and related |
2 | functions. | |
d614a753 | 3 | Copyright (C) 2012-2020 Free Software Foundation, Inc. |
46692946 PM |
4 | This file is part of the GNU C Library. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Lesser General Public | |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
10 | ||
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public | |
17 | License along with the GNU C Library; if not, see | |
5a82c748 | 18 | <https://www.gnu.org/licenses/>. */ |
46692946 PM |
19 | |
20 | /* Defining _LIBC_TEST ensures long double math functions are | |
21 | declared in the headers. */ | |
22 | #define _LIBC_TEST 1 | |
46453c3c | 23 | #define __STDC_WANT_IEC_60559_TYPES_EXT__ |
46692946 PM |
24 | #include <fenv.h> |
25 | #include <float.h> | |
26 | #include <math.h> | |
27 | #include <stdbool.h> | |
28 | #include <stdio.h> | |
29 | #include <stdlib.h> | |
30 | #include <string.h> | |
31 | #include <math-tests.h> | |
32 | ||
33 | #include "tst-strtod.h" | |
34 | ||
35 | /* Non-standard macros expected to be externally defined: | |
36 | ||
37 | L_(str): Pastes the appropriate modifier to a string literal str. | |
38 | ||
39 | FNPFX: Expands to the correct prefix for the strtod equivalent | |
40 | of type CHAR. (e.g str or wcs). | |
41 | ||
42 | CHAR: Expands to the string type being tested (e.g wchar_t or char). | |
43 | ||
44 | STRM: Expands to a string literal suitable for printing CHAR* via | |
45 | printf (e.g "%s" or "%ls"). */ | |
46 | ||
47 | #define _CONCAT(a, b) a ## b | |
48 | #define CONCAT(a, b) _CONCAT (a, b) | |
49 | ||
50 | #define STRTO(x) CONCAT (CONCAT (FNPFX, to), x) | |
51 | ||
52 | #if LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024 | |
53 | /* This is a stupid hack for IBM long double. This test ignores | |
54 | inexact values for long double due to the limitations of the | |
55 | format. This ensures rounding tests are ignored. */ | |
56 | # undef ROUNDING_TESTS_long_double | |
57 | # define ROUNDING_TESTS_long_double(x) 0 | |
58 | #endif | |
59 | ||
60 | /* Generator to create an FTYPE member variabled named FSUF | |
61 | used to populate struct member variables. */ | |
bf5eea32 | 62 | #define FTYPE_MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \ |
46692946 PM |
63 | FTYPE FSUF; |
64 | ||
65 | /* Likewise, but each member is of type bool. */ | |
bf5eea32 | 66 | #define BOOL_MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \ |
46692946 PM |
67 | bool FSUF; |
68 | ||
69 | #define STRUCT_FOREACH_FLOAT_FTYPE GEN_TEST_STRTOD_FOREACH (FTYPE_MEMBER) | |
70 | #define STRUCT_FOREACH_FLOAT_BOOL GEN_TEST_STRTOD_FOREACH (BOOL_MEMBER) | |
71 | ||
72 | /* Define the long double choose (CHOOSE_ld) macro | |
73 | to select the appropriate generated long double | |
74 | value from the generated test data. */ | |
75 | #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 | |
76 | /* This is for the long double == double format. */ | |
77 | # define CHOOSE_ld(f,d,...) d | |
78 | #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16381 | |
79 | /* This is for the Intel extended float format. */ | |
80 | # define CHOOSE_ld(f,d,ld64i,...) ld64i | |
81 | #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16382 | |
82 | /* This is for the Motorola extended float format. */ | |
83 | # define CHOOSE_ld(f,d,ld64i,ld64m,...) ld64m | |
84 | #elif LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024 | |
85 | /* This is for the IBM extended double format. */ | |
86 | # define CHOOSE_ld(f,d,ld64i,ld64m,ld106,...) ld106 | |
87 | #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 | |
88 | /* This is for the IEEE binary128 format. */ | |
89 | # define CHOOSE_ld(f,d,ld64i,ld64m,ld106,ld113,...) ld113 | |
90 | #else | |
91 | # error "unknown long double format" | |
92 | #endif | |
93 | ||
94 | /* Add type specific choosing macros below. */ | |
95 | #define CHOOSE_f(f,...) f | |
58c4a161 | 96 | #define CHOOSE_f32(f,...) f |
46692946 | 97 | #define CHOOSE_d(f,d,...) d |
58c4a161 JM |
98 | #define CHOOSE_f64(f,d,...) d |
99 | #define CHOOSE_f32x(f,d,...) d | |
45f39d45 | 100 | #define CHOOSE_f128(f,d,ld64i,ld64m,ld106,ld113,...) ld113 |
58c4a161 JM |
101 | /* long double is special, and handled above. _Float16 would require |
102 | updates to the generator to generate appropriate expectations, and | |
103 | updates to the test inputs to cover difficult rounding cases for | |
104 | _Float16. */ | |
105 | ||
106 | #if __HAVE_FLOAT64X | |
107 | # if FLT64X_MANT_DIG == 113 && FLT64X_MAX_EXP == 16384 | |
108 | # define CHOOSE_f64x(f,d,ld64i,ld64m,ld106,ld113,...) ld113 | |
109 | # elif (FLT64X_MANT_DIG == 64 \ | |
110 | && FLT64X_MAX_EXP == 16384 \ | |
111 | && FLT64X_MIN_EXP == -16381) | |
112 | # define CHOOSE_f64x(f,d,ld64i,...) ld64i | |
113 | # else | |
114 | # error "unknown _Float64x format" | |
115 | # endif | |
116 | #endif | |
46692946 PM |
117 | |
118 | /* Selector for expected result field of a given type. */ | |
bf5eea32 | 119 | #define _ENTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...) \ |
46692946 PM |
120 | CONCAT (CHOOSE_ ## FSUF (__VA_ARGS__), LSUF), |
121 | #define ENTRY(...) \ | |
122 | GEN_TEST_STRTOD_FOREACH (_ENTRY, __VA_ARGS__) | |
123 | ||
fcd6b5ac JM |
124 | /* Selector for boolean exact tag of expected results and that for |
125 | overflow. */ | |
bf5eea32 | 126 | #define _XNTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...) \ |
46692946 PM |
127 | CHOOSE_ ## FSUF (__VA_ARGS__), |
128 | #define XNTRY(...) \ | |
129 | GEN_TEST_STRTOD_FOREACH (_XNTRY, __VA_ARGS__) | |
130 | ||
131 | /* This is hacky way around the seemingly unavoidable macro | |
132 | expansion of the INFINITY or HUGE_VAL like macros in the | |
133 | above. It is assumed the compiler will implicitly convert | |
134 | the infinity correctly. */ | |
135 | #define INF INFINITY + 0.0 | |
136 | ||
137 | /* This macro is used in conjunction with the output from the | |
138 | gen-tst-strtod-round utility to select the appropriately | |
139 | rounded long double value for a given format. */ | |
fcd6b5ac JM |
140 | #define TEST(s, \ |
141 | fx, fd, fdo, fn, fno, fz, fzo, fu, fuo, \ | |
142 | dx, dd, ddo, dn, dno, dz, dzo, du, duo, \ | |
143 | ld64ix, ld64id, ld64ido, ld64in, ld64ino, \ | |
144 | ld64iz, ld64izo, ld64iu, ld64iuo, \ | |
145 | ld64mx, ld64md, ld64mdo, ld64mn, ld64mno, \ | |
146 | ld64mz, ld64mzo, ld64mu, ld64muo, \ | |
147 | ld106x, ld106d, ld106do, ld106n, ld106no, \ | |
148 | ld106z, ld106zo, ld106u, ld106uo, \ | |
149 | ld113x, ld113d, ld113do, ld113n, ld113no, \ | |
150 | ld113z, ld113zo, ld113u, ld113uo) \ | |
151 | { \ | |
152 | L_ (s), \ | |
153 | { XNTRY (fx, dx, ld64ix, ld64mx, ld106x, ld113x) }, \ | |
154 | { \ | |
155 | { ENTRY (fn, dn, ld64in, ld64mn, ld106n, ld113n) }, \ | |
156 | { ENTRY (fd, dd, ld64id, ld64md, ld106d, ld113d) }, \ | |
157 | { ENTRY (fz, dz, ld64iz, ld64mz, ld106z, ld113z) }, \ | |
158 | { ENTRY (fu, du, ld64iu, ld64mu, ld106u, ld113u) } \ | |
159 | }, \ | |
160 | { \ | |
161 | { XNTRY (fno, dno, ld64ino, ld64mno, ld106no, ld113no) }, \ | |
162 | { XNTRY (fdo, ddo, ld64ido, ld64mdo, ld106do, ld113do) }, \ | |
163 | { XNTRY (fzo, dzo, ld64izo, ld64mzo, ld106zo, ld113zo) }, \ | |
164 | { XNTRY (fuo, duo, ld64iuo, ld64muo, ld106uo, ld113uo) } \ | |
165 | } \ | |
46692946 PM |
166 | } |
167 | ||
168 | struct test_exactness | |
169 | { | |
170 | STRUCT_FOREACH_FLOAT_BOOL | |
171 | }; | |
172 | ||
173 | struct test_results | |
174 | { | |
175 | STRUCT_FOREACH_FLOAT_FTYPE | |
176 | }; | |
177 | ||
fcd6b5ac JM |
178 | struct test_overflow |
179 | { | |
180 | STRUCT_FOREACH_FLOAT_BOOL | |
181 | }; | |
182 | ||
46692946 PM |
183 | struct test { |
184 | const CHAR *s; | |
185 | struct test_exactness exact; | |
186 | struct test_results r[4]; | |
fcd6b5ac | 187 | struct test_overflow o[4]; |
46692946 PM |
188 | }; |
189 | ||
190 | /* Include the generated test data. */ | |
191 | #include "tst-strtod-round-data.h" | |
192 | ||
193 | #define STRX(x) #x | |
194 | #define STR(x) STRX (x) | |
195 | #define FNPFXS STR (FNPFX) | |
196 | ||
4725d33e JM |
197 | #ifndef FE_INEXACT |
198 | # define FE_INEXACT 0 | |
199 | #endif | |
200 | ||
fcd6b5ac JM |
201 | #ifndef FE_OVERFLOW |
202 | # define FE_OVERFLOW 0 | |
203 | #endif | |
204 | ||
bf5eea32 | 205 | #define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \ |
46692946 | 206 | { \ |
fcd6b5ac | 207 | feclearexcept (FE_ALL_EXCEPT); \ |
46692946 PM |
208 | FTYPE f = STRTO (FSUF) (s, NULL); \ |
209 | if (f != expected->FSUF \ | |
210 | || (copysign ## CSUF) (1.0 ## LSUF, f) \ | |
211 | != (copysign ## CSUF) (1.0 ## LSUF, expected->FSUF)) \ | |
212 | { \ | |
bf5eea32 RS |
213 | char efstr[FSTRLENMAX]; \ |
214 | char fstr[FSTRLENMAX]; \ | |
215 | FTOSTR (efstr, FSTRLENMAX, "%a", expected->FSUF); \ | |
216 | FTOSTR (fstr, FSTRLENMAX, "%a", f); \ | |
217 | printf (FNPFXS "to" #FSUF " (" STRM ") returned %s not " \ | |
218 | "%s (%s)\n", s, fstr, efstr, mode_name); \ | |
46692946 PM |
219 | if (ROUNDING_TESTS (FTYPE, rnd_mode) || exact->FSUF) \ |
220 | result = 1; \ | |
221 | else \ | |
222 | printf ("ignoring this inexact result\n"); \ | |
223 | } \ | |
fcd6b5ac | 224 | else \ |
4725d33e | 225 | { \ |
fcd6b5ac JM |
226 | if (FE_INEXACT != 0) \ |
227 | { \ | |
228 | bool inexact_raised = fetestexcept (FE_INEXACT) != 0; \ | |
229 | if (inexact_raised != !exact->FSUF) \ | |
230 | { \ | |
231 | printf (FNPFXS "to" #FSUF \ | |
232 | " (" STRM ") inexact %d " \ | |
233 | "not %d\n", s, inexact_raised, \ | |
234 | !exact->FSUF); \ | |
235 | if (EXCEPTION_TESTS (FTYPE)) \ | |
236 | result = 1; \ | |
237 | else \ | |
238 | printf ("ignoring this exception error\n"); \ | |
239 | } \ | |
240 | } \ | |
241 | if (FE_OVERFLOW != 0) \ | |
4725d33e | 242 | { \ |
fcd6b5ac JM |
243 | bool overflow_raised \ |
244 | = fetestexcept (FE_OVERFLOW) != 0; \ | |
245 | if (overflow_raised != overflow->FSUF) \ | |
246 | { \ | |
247 | printf (FNPFXS "to" #FSUF \ | |
248 | " (" STRM ") overflow %d " \ | |
249 | "not %d\n", s, overflow_raised, \ | |
250 | overflow->FSUF); \ | |
251 | if (EXCEPTION_TESTS (FTYPE)) \ | |
252 | result = 1; \ | |
253 | else \ | |
254 | printf ("ignoring this exception error\n"); \ | |
255 | } \ | |
4725d33e JM |
256 | } \ |
257 | } \ | |
46692946 PM |
258 | } |
259 | ||
260 | static int | |
261 | test_in_one_mode (const CHAR *s, const struct test_results *expected, | |
fcd6b5ac JM |
262 | const struct test_exactness *exact, |
263 | const struct test_overflow *overflow, | |
264 | const char *mode_name, int rnd_mode) | |
46692946 PM |
265 | { |
266 | int result = 0; | |
267 | GEN_TEST_STRTOD_FOREACH (GEN_ONE_TEST) | |
268 | return result; | |
269 | } | |
270 | ||
271 | static const struct fetestmodes | |
272 | { | |
273 | const char *mode_name; | |
274 | int rnd_mode; | |
275 | int rnd_i; /* Corresponding index into r array of struct test. */ | |
276 | } modes[] = { | |
277 | { "default rounding mode", FE_TONEAREST, 0 }, | |
278 | #ifdef FE_DOWNWARD | |
279 | { "FE_DOWNWARD", FE_DOWNWARD, 1 }, | |
280 | #endif | |
281 | #ifdef FE_TOWARDZERO | |
282 | { "FE_TOWARDZERO", FE_TOWARDZERO, 2 }, | |
283 | #endif | |
284 | #ifdef FE_UPWARD | |
285 | { "FE_UPWARD", FE_UPWARD, 3 }, | |
286 | #endif | |
287 | {} | |
288 | }; | |
289 | ||
290 | static int | |
291 | do_test (void) | |
292 | { | |
293 | int save_round_mode __attribute__ ((unused)) = fegetround (); | |
294 | int result = 0; | |
295 | for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) | |
296 | { | |
297 | result |= test_in_one_mode (tests[i].s, &tests[i].r[modes[0].rnd_i], | |
fcd6b5ac JM |
298 | &tests[i].exact, &tests[i].o[modes[0].rnd_i], |
299 | modes[0].mode_name, modes[0].rnd_mode); | |
46692946 PM |
300 | for (const struct fetestmodes *m = &modes[1]; m->mode_name != NULL; m++) |
301 | { | |
302 | if (!fesetround (m->rnd_mode)) | |
303 | { | |
304 | result |= test_in_one_mode (tests[i].s, &tests[i].r[m->rnd_i], | |
fcd6b5ac JM |
305 | &tests[i].exact, |
306 | &tests[i].o[m->rnd_i], m->mode_name, | |
46692946 PM |
307 | m->rnd_mode); |
308 | fesetround (save_round_mode); | |
309 | } | |
310 | } | |
311 | } | |
312 | return result; | |
313 | } | |
314 | ||
315 | #define TEST_FUNCTION do_test () | |
316 | #include "../test-skeleton.c" |