1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2020 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #define _GNU_SOURCE
37 #include <fenv.h>
38 #include <math.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <errno.h>
43 #include <limits.h>
44
45 static const char *
e_to_str(int e)46 e_to_str(int e)
47 {
48 if (e == 0)
49 return "NONE";
50
51 #ifdef FE_DIVBYZERO
52 if (e == FE_DIVBYZERO)
53 return "FE_DIVBYZERO";
54 #endif
55 #ifdef FE_OVERFLOW
56 if (e == FE_OVERFLOW)
57 return "FE_OVERFLOW";
58 #endif
59 #ifdef FE_UNDERFLOW
60 if (e == FE_UNDERFLOW)
61 return "FE_UNDERFLOW";
62 #endif
63 #ifdef FE_INEXACT
64 if (e == FE_INEXACT)
65 return "FE_INEXACT";
66 #endif
67 #ifdef FE_INVALID
68 if (e == FE_INVALID)
69 return "FE_INVALID";
70 #endif
71 #if defined(FE_OVERFLOW) && defined(FE_INEXACT)
72 if (e == (FE_OVERFLOW|FE_INEXACT))
73 return "FE_OVERFLOW|FE_INEXACT";
74 #endif
75 #if defined(FE_UNDERFLOW) && defined(FE_INEXACT)
76 if (e == (FE_UNDERFLOW|FE_INEXACT))
77 return "FE_UNDERFLOW|FE_INEXACT";
78 #endif
79 static char buf[3][128];
80 static int i = 0;
81 buf[i][0] = '\0';
82 while (e) {
83 char *v = NULL;
84 char tmp[24];
85 #ifdef FE_DIVBYZERO
86 if (e & FE_DIVBYZERO) {
87 v = "FE_DIVBYZERO";
88 e &= ~FE_DIVBYZERO;
89 } else
90 #endif
91 #ifdef FE_OVERFLOW
92 if (e & FE_OVERFLOW) {
93 v = "FE_OVERFLOW";
94 e &= ~FE_OVERFLOW;
95 } else
96 #endif
97 #ifdef FE_UNDERFLOW
98 if (e & FE_UNDERFLOW) {
99 v = "FE_UNDERFLOW";
100 e &= ~FE_UNDERFLOW;
101 } else
102 #endif
103 #ifdef FE_INEXACT
104 if (e & FE_INEXACT) {
105 v = "FE_INEXACT";
106 e &= ~FE_INEXACT;
107 } else
108 #endif
109 #ifdef FE_INVALID
110 if (e & FE_INVALID) {
111 v = "FE_INVALID";
112 e &= ~FE_INVALID;
113 } else
114 #endif
115 {
116 snprintf(tmp, sizeof(tmp), "?? 0x%x", e);
117 v = tmp;
118 e = 0;
119 }
120 #define check_add(s) do { \
121 if (strlen(buf[i]) + strlen(s) + 1 > sizeof(buf[i])) \
122 printf("exception buf overflow %s + %s\n", buf[i], s); \
123 else \
124 strcat(buf[i], s); \
125 } while(0)
126 if (buf[i][0])
127 check_add(" | ");
128 check_add(v);
129 }
130 char *ret = buf[i];
131 i = (i + 1) % 3;
132 return ret;
133 }
134
135 #define scat(a,b) a ## b
136
137 /* Tests with long doubles */
138 #ifdef __SIZEOF_LONG_DOUBLE__
139
140 #if defined(__PICOLIBC__) && !defined(_HAVE_LONG_DOUBLE_MATH)
141 #define SIMPLE_MATH_ONLY
142 #define NO_NEXTTOWARD
143 #endif
144
145 #ifdef PICOLIBC_LONG_DOUBLE_NOEXCEPT
146 #define EXCEPTION_TEST 0
147 #else
148 #define EXCEPTION_TEST MATH_ERREXCEPT
149 #endif
150 #define LONG_DOUBLE_EXCEPTION_TEST EXCEPTION_TEST
151 #ifdef _M_PI_L
152 #define PI_VAL _M_PI_L
153 #else
154 #define PI_VAL 3.141592653589793238462643383279502884L
155 #endif
156
157 #ifdef __PICOLIBC__
158 #define NO_BESSEL_TESTS
159 #endif
160
161 #define _PASTE_LDBL(exp) 0x.fp ## exp ## L
162 #define PASTE_LDBL(exp) _PASTE_LDBL(exp)
163
164 #define BIG PASTE_LDBL(__LDBL_MAX_EXP__)
165 #if __LDBL_MANT_DIG__ >= 64
166 #define BIGODD 0x1.123456789abcdef2p+63l
167 #define BIGEVEN 0x1.123456789abcdef0p+63l
168 #else
169 #define BIGODD 0x1.123456789abcdp+52
170 #define BIGEVEN 0x1.123456789abccp+52
171 #endif
172 #define SMALL __LDBL_DENORM_MIN__
173 #define FLOAT_T long double
174 #define MIN_VAL __LDBL_DENORM_MIN__
175 #define MAX_VAL __LDBL_MAX__
176 #define EPSILON_VAL __LDBL_EPSILON__
177 #define sNAN __builtin_nansl("")
178
179 #define TEST_LONG_DOUBLE
180
181 #define makemathname(s) scat(s,l)
182 #define makemathname_r(s) scat(s,l_r)
183
184 #include "math_errhandling_tests.c"
185
186 #undef BIG
187 #undef BIGODD
188 #undef BIGEVEN
189 #undef SMALL
190 #undef MIN_VAL
191 #undef MAX_VAL
192 #undef EPSILON_VAL
193 #undef sNAN
194 #undef makemathname
195 #undef makemathname_r
196 #undef FLOAT_T
197 #undef EXCEPTION_TEST
198 #undef TEST_LONG_DOUBLE
199 #undef NO_BESSEL_TESTS
200 #undef PI_VAL
201 #undef SIMPLE_MATH_ONLY
202 #endif
203
204 /* Tests with doubles */
205 #ifdef PICOLIBC_DOUBLE_NOEXCEPT
206 #define EXCEPTION_TEST 0
207 #else
208 #define EXCEPTION_TEST MATH_ERREXCEPT
209 #endif
210 #define DOUBLE_EXCEPTION_TEST EXCEPTION_TEST
211
212 #define BIG 1.7e308
213 #define BIGODD 0x1.123456789abcdp+52
214 #define BIGEVEN 0x1.123456789abccp+52
215 #define SMALL 5e-324
216 #define FLOAT_T double
217 #define MIN_VAL __DBL_DENORM_MIN__
218 #define MAX_VAL __DBL_MAX__
219 #define EPSILON_VAL __DBL_EPSILON__
220 #define sNAN __builtin_nans("")
221 #define PI_VAL M_PI
222
223 #define TEST_DOUBLE
224
225 #define makemathname(s) s
226 #define makemathname_r(s) scat(s,_r)
227
228 #include "math_errhandling_tests.c"
229
230 #undef BIG
231 #undef BIGODD
232 #undef BIGEVEN
233 #undef SMALL
234 #undef MIN_VAL
235 #undef MAX_VAL
236 #undef EPSILON_VAL
237 #undef sNAN
238 #undef makemathname
239 #undef makemathname_r
240 #undef FLOAT_T
241 #undef EXCEPTION_TEST
242 #undef TEST_DOUBLE
243 #undef PI_VAL
244
245 /* Tests with floats */
246 #define EXCEPTION_TEST MATH_ERREXCEPT
247 #define BIG 3e38
248 #define BIGODD 0x1.123456p+23
249 #define BIGEVEN 0x1.123454p+23
250 #define SMALL 1e-45
251 #define MIN_VAL 0x8p-152f
252 #define MAX_VAL 0xf.fffffp+124f
253 #define EPSILON_VAL 0x1p-23f
254 #define sNAN __builtin_nansf("")
255 #define FLOAT_T float
256 #define TEST_FLOAT
257 #define makemathname(s) scat(s,f)
258 #define makemathname_r(s) scat(s,f_r)
259 #define PI_VAL ((float) M_PI)
260
261 #include "math_errhandling_tests.c"
262
main(void)263 int main(void)
264 {
265 int result = 0;
266
267 #if DOUBLE_EXCEPTION_TEST
268 printf("Double tests:\n");
269 result += run_tests();
270 #endif
271 #ifdef LONG_DOUBLE_EXCEPTION_TEST
272 printf("Long double tests:\n");
273 result += run_testsl();
274 #endif
275 printf("Float tests:\n");
276 result += run_testsf();
277 return result;
278 }
279