]> git.ipfire.org Git - thirdparty/glibc.git/blame - math/math-narrow.h
Fix f64xdivf128, f64xmulf128 spurious underflows (bug 28358)
[thirdparty/glibc.git] / math / math-narrow.h
CommitLineData
63716ab2 1/* Helper macros for functions returning a narrower type.
2b778ceb 2 Copyright (C) 2018-2021 Free Software Foundation, Inc.
63716ab2
JM
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
63716ab2
JM
18
19#ifndef _MATH_NARROW_H
20#define _MATH_NARROW_H 1
21
22#include <bits/floatn.h>
23#include <bits/long-double.h>
24#include <errno.h>
25#include <fenv.h>
26#include <ieee754.h>
b4d5b8b0 27#include <math-barriers.h>
63716ab2 28#include <math_private.h>
70e2ba33 29#include <fenv_private.h>
abd38358 30#include <math-narrow-alias.h>
1356f38d 31#include <stdbool.h>
63716ab2
JM
32
33/* Carry out a computation using round-to-odd. The computation is
34 EXPR; the union type in which to store the result is UNION and the
35 subfield of the "ieee" field of that union with the low part of the
abd38358
JM
36 mantissa is MANTISSA; SUFFIX is the suffix for both underlying libm
37 functions for the argument type (for computations where a libm
38 function rather than a C operator is used when argument and result
39 types are the same) and the libc_fe* macros to ensure that the
40 correct rounding mode is used, for platforms with multiple rounding
1356f38d
JM
41 modes where those macros set only the relevant mode.
42 CLEAR_UNDERFLOW indicates whether underflow exceptions must be
43 cleared (in the case where a round-toward-zero underflow might not
44 indicate an underflow after narrowing, when that narrowing only
45 reduces precision not exponent range and the architecture uses
46 before-rounding tininess detection). This macro does not work
47 correctly if the sign of an exact zero result depends on the
48 rounding mode, so that case must be checked for separately. */
49#define ROUND_TO_ODD(EXPR, UNION, SUFFIX, MANTISSA, CLEAR_UNDERFLOW) \
63716ab2
JM
50 ({ \
51 fenv_t env; \
52 UNION u; \
53 \
54 libc_feholdexcept_setround ## SUFFIX (&env, FE_TOWARDZERO); \
55 u.d = (EXPR); \
56 math_force_eval (u.d); \
1356f38d
JM
57 if (CLEAR_UNDERFLOW) \
58 feclearexcept (FE_UNDERFLOW); \
63716ab2
JM
59 u.ieee.MANTISSA \
60 |= libc_feupdateenv_test ## SUFFIX (&env, FE_INEXACT) != 0; \
61 \
62 u.d; \
63 })
64
d8742dd8
JM
65/* Check for error conditions from a narrowing add function returning
66 RET with arguments X and Y and set errno as needed. Overflow and
67 underflow can occur for finite arguments and a domain error for
68 infinite ones. */
69#define CHECK_NARROW_ADD(RET, X, Y) \
70 do \
71 { \
72 if (!isfinite (RET)) \
73 { \
74 if (isnan (RET)) \
75 { \
76 if (!isnan (X) && !isnan (Y)) \
77 __set_errno (EDOM); \
78 } \
79 else if (isfinite (X) && isfinite (Y)) \
80 __set_errno (ERANGE); \
81 } \
82 else if ((RET) == 0 && (X) != -(Y)) \
83 __set_errno (ERANGE); \
84 } \
85 while (0)
86
87/* Implement narrowing add using round-to-odd. The arguments are X
88 and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are
89 as for ROUND_TO_ODD. */
90#define NARROW_ADD_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \
91 do \
92 { \
93 TYPE ret; \
94 \
95 /* Ensure a zero result is computed in the original rounding \
96 mode. */ \
97 if ((X) == -(Y)) \
98 ret = (TYPE) ((X) + (Y)); \
99 else \
100 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) + (Y), \
1356f38d 101 UNION, SUFFIX, MANTISSA, false); \
d8742dd8
JM
102 \
103 CHECK_NARROW_ADD (ret, (X), (Y)); \
104 return ret; \
105 } \
106 while (0)
107
108/* Implement a narrowing add function that is not actually narrowing
109 or where no attempt is made to be correctly rounding (the latter
110 only applies to IBM long double). The arguments are X and Y and
111 the return type is TYPE. */
112#define NARROW_ADD_TRIVIAL(X, Y, TYPE) \
113 do \
114 { \
115 TYPE ret; \
116 \
117 ret = (TYPE) ((X) + (Y)); \
118 CHECK_NARROW_ADD (ret, (X), (Y)); \
119 return ret; \
120 } \
121 while (0)
122
8d3f9e85
JM
123/* Check for error conditions from a narrowing subtract function
124 returning RET with arguments X and Y and set errno as needed.
125 Overflow and underflow can occur for finite arguments and a domain
126 error for infinite ones. */
127#define CHECK_NARROW_SUB(RET, X, Y) \
128 do \
129 { \
130 if (!isfinite (RET)) \
131 { \
132 if (isnan (RET)) \
133 { \
134 if (!isnan (X) && !isnan (Y)) \
135 __set_errno (EDOM); \
136 } \
137 else if (isfinite (X) && isfinite (Y)) \
138 __set_errno (ERANGE); \
139 } \
140 else if ((RET) == 0 && (X) != (Y)) \
141 __set_errno (ERANGE); \
142 } \
143 while (0)
144
145/* Implement narrowing subtract using round-to-odd. The arguments are
146 X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are
147 as for ROUND_TO_ODD. */
148#define NARROW_SUB_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA) \
149 do \
150 { \
151 TYPE ret; \
152 \
153 /* Ensure a zero result is computed in the original rounding \
154 mode. */ \
155 if ((X) == (Y)) \
156 ret = (TYPE) ((X) - (Y)); \
157 else \
158 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) - (Y), \
1356f38d 159 UNION, SUFFIX, MANTISSA, false); \
8d3f9e85
JM
160 \
161 CHECK_NARROW_SUB (ret, (X), (Y)); \
162 return ret; \
163 } \
164 while (0)
165
166/* Implement a narrowing subtract function that is not actually
167 narrowing or where no attempt is made to be correctly rounding (the
168 latter only applies to IBM long double). The arguments are X and Y
169 and the return type is TYPE. */
170#define NARROW_SUB_TRIVIAL(X, Y, TYPE) \
171 do \
172 { \
173 TYPE ret; \
174 \
175 ret = (TYPE) ((X) - (Y)); \
176 CHECK_NARROW_SUB (ret, (X), (Y)); \
177 return ret; \
178 } \
179 while (0)
180
69a01461
JM
181/* Check for error conditions from a narrowing multiply function
182 returning RET with arguments X and Y and set errno as needed.
183 Overflow and underflow can occur for finite arguments and a domain
184 error for Inf * 0. */
185#define CHECK_NARROW_MUL(RET, X, Y) \
186 do \
187 { \
188 if (!isfinite (RET)) \
189 { \
190 if (isnan (RET)) \
191 { \
192 if (!isnan (X) && !isnan (Y)) \
193 __set_errno (EDOM); \
194 } \
195 else if (isfinite (X) && isfinite (Y)) \
196 __set_errno (ERANGE); \
197 } \
198 else if ((RET) == 0 && (X) != 0 && (Y) != 0) \
199 __set_errno (ERANGE); \
200 } \
201 while (0)
202
203/* Implement narrowing multiply using round-to-odd. The arguments are
1356f38d
JM
204 X and Y, the return type is TYPE and UNION, MANTISSA, SUFFIX and
205 CLEAR_UNDERFLOW are as for ROUND_TO_ODD. */
206#define NARROW_MUL_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA, \
207 CLEAR_UNDERFLOW) \
69a01461
JM
208 do \
209 { \
210 TYPE ret; \
211 \
212 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) * (Y), \
1356f38d
JM
213 UNION, SUFFIX, MANTISSA, \
214 CLEAR_UNDERFLOW); \
69a01461
JM
215 \
216 CHECK_NARROW_MUL (ret, (X), (Y)); \
217 return ret; \
218 } \
219 while (0)
220
221/* Implement a narrowing multiply function that is not actually
222 narrowing or where no attempt is made to be correctly rounding (the
223 latter only applies to IBM long double). The arguments are X and Y
224 and the return type is TYPE. */
225#define NARROW_MUL_TRIVIAL(X, Y, TYPE) \
226 do \
227 { \
228 TYPE ret; \
229 \
230 ret = (TYPE) ((X) * (Y)); \
231 CHECK_NARROW_MUL (ret, (X), (Y)); \
232 return ret; \
233 } \
234 while (0)
235
632a6cbe
JM
236/* Check for error conditions from a narrowing divide function
237 returning RET with arguments X and Y and set errno as needed.
238 Overflow, underflow and divide-by-zero can occur for finite
239 arguments and a domain error for Inf / Inf and 0 / 0. */
240#define CHECK_NARROW_DIV(RET, X, Y) \
241 do \
242 { \
243 if (!isfinite (RET)) \
244 { \
245 if (isnan (RET)) \
246 { \
247 if (!isnan (X) && !isnan (Y)) \
248 __set_errno (EDOM); \
249 } \
250 else if (isfinite (X)) \
251 __set_errno (ERANGE); \
252 } \
253 else if ((RET) == 0 && (X) != 0 && !isinf (Y)) \
254 __set_errno (ERANGE); \
255 } \
256 while (0)
257
1356f38d
JM
258/* Implement narrowing divide using round-to-odd. The arguments are X
259 and Y, the return type is TYPE and UNION, MANTISSA, SUFFIX and
260 CLEAR_UNDERFLOW are as for ROUND_TO_ODD. */
261#define NARROW_DIV_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA, \
262 CLEAR_UNDERFLOW) \
632a6cbe
JM
263 do \
264 { \
265 TYPE ret; \
266 \
267 ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) / (Y), \
1356f38d
JM
268 UNION, SUFFIX, MANTISSA, \
269 CLEAR_UNDERFLOW); \
632a6cbe
JM
270 \
271 CHECK_NARROW_DIV (ret, (X), (Y)); \
272 return ret; \
273 } \
274 while (0)
275
276/* Implement a narrowing divide function that is not actually
277 narrowing or where no attempt is made to be correctly rounding (the
278 latter only applies to IBM long double). The arguments are X and Y
279 and the return type is TYPE. */
280#define NARROW_DIV_TRIVIAL(X, Y, TYPE) \
281 do \
282 { \
283 TYPE ret; \
284 \
285 ret = (TYPE) ((X) / (Y)); \
286 CHECK_NARROW_DIV (ret, (X), (Y)); \
287 return ret; \
288 } \
289 while (0)
290
abd38358
JM
291/* Check for error conditions from a narrowing square root function
292 returning RET with argument X and set errno as needed. Overflow
293 and underflow can occur for finite positive arguments and a domain
294 error for negative arguments. */
295#define CHECK_NARROW_SQRT(RET, X) \
296 do \
297 { \
298 if (!isfinite (RET)) \
299 { \
300 if (isnan (RET)) \
301 { \
302 if (!isnan (X)) \
303 __set_errno (EDOM); \
304 } \
305 else if (isfinite (X)) \
306 __set_errno (ERANGE); \
307 } \
308 else if ((RET) == 0 && (X) != 0) \
309 __set_errno (ERANGE); \
310 } \
311 while (0)
63716ab2 312
abd38358
JM
313/* Implement narrowing square root using round-to-odd. The argument
314 is X, the return type is TYPE and UNION, MANTISSA and SUFFIX are as
315 for ROUND_TO_ODD. */
316#define NARROW_SQRT_ROUND_TO_ODD(X, TYPE, UNION, SUFFIX, MANTISSA) \
317 do \
318 { \
319 TYPE ret; \
320 \
321 ret = (TYPE) ROUND_TO_ODD (sqrt ## SUFFIX (math_opt_barrier (X)), \
1356f38d 322 UNION, SUFFIX, MANTISSA, false); \
abd38358
JM
323 \
324 CHECK_NARROW_SQRT (ret, (X)); \
325 return ret; \
326 } \
327 while (0)
63716ab2 328
abd38358
JM
329/* Implement a narrowing square root function where no attempt is made
330 to be correctly rounding (this only applies to IBM long double; the
331 case where the function is not actually narrowing is handled by
332 aliasing other sqrt functions in libm, not using this macro). The
333 argument is X and the return type is TYPE. */
334#define NARROW_SQRT_TRIVIAL(X, TYPE, SUFFIX) \
335 do \
336 { \
337 TYPE ret; \
338 \
339 ret = (TYPE) (sqrt ## SUFFIX (X)); \
340 CHECK_NARROW_SQRT (ret, (X)); \
341 return ret; \
342 } \
343 while (0)
63716ab2
JM
344
345#endif /* math-narrow.h. */