xref: /freebsd/contrib/arm-optimized-routines/math/math_errf.c (revision 31914882fca502069810b9e9ddea4bcd8136a4f4)
1*31914882SAlex Richardson /*
2*31914882SAlex Richardson  * Single-precision math error handling.
3*31914882SAlex Richardson  *
4*31914882SAlex Richardson  * Copyright (c) 2017-2020, Arm Limited.
5*31914882SAlex Richardson  * SPDX-License-Identifier: MIT
6*31914882SAlex Richardson  */
7*31914882SAlex Richardson 
8*31914882SAlex Richardson #include "math_config.h"
9*31914882SAlex Richardson 
10*31914882SAlex Richardson #if WANT_ERRNO
11*31914882SAlex Richardson #include <errno.h>
12*31914882SAlex Richardson /* NOINLINE reduces code size and avoids making math functions non-leaf
13*31914882SAlex Richardson    when the error handling is inlined.  */
14*31914882SAlex Richardson NOINLINE static float
15*31914882SAlex Richardson with_errnof (float y, int e)
16*31914882SAlex Richardson {
17*31914882SAlex Richardson   errno = e;
18*31914882SAlex Richardson   return y;
19*31914882SAlex Richardson }
20*31914882SAlex Richardson #else
21*31914882SAlex Richardson #define with_errnof(x, e) (x)
22*31914882SAlex Richardson #endif
23*31914882SAlex Richardson 
24*31914882SAlex Richardson /* NOINLINE reduces code size.  */
25*31914882SAlex Richardson NOINLINE static float
26*31914882SAlex Richardson xflowf (uint32_t sign, float y)
27*31914882SAlex Richardson {
28*31914882SAlex Richardson   y = eval_as_float (opt_barrier_float (sign ? -y : y) * y);
29*31914882SAlex Richardson   return with_errnof (y, ERANGE);
30*31914882SAlex Richardson }
31*31914882SAlex Richardson 
32*31914882SAlex Richardson HIDDEN float
33*31914882SAlex Richardson __math_uflowf (uint32_t sign)
34*31914882SAlex Richardson {
35*31914882SAlex Richardson   return xflowf (sign, 0x1p-95f);
36*31914882SAlex Richardson }
37*31914882SAlex Richardson 
38*31914882SAlex Richardson #if WANT_ERRNO_UFLOW
39*31914882SAlex Richardson /* Underflows to zero in some non-nearest rounding mode, setting errno
40*31914882SAlex Richardson    is valid even if the result is non-zero, but in the subnormal range.  */
41*31914882SAlex Richardson HIDDEN float
42*31914882SAlex Richardson __math_may_uflowf (uint32_t sign)
43*31914882SAlex Richardson {
44*31914882SAlex Richardson   return xflowf (sign, 0x1.4p-75f);
45*31914882SAlex Richardson }
46*31914882SAlex Richardson #endif
47*31914882SAlex Richardson 
48*31914882SAlex Richardson HIDDEN float
49*31914882SAlex Richardson __math_oflowf (uint32_t sign)
50*31914882SAlex Richardson {
51*31914882SAlex Richardson   return xflowf (sign, 0x1p97f);
52*31914882SAlex Richardson }
53*31914882SAlex Richardson 
54*31914882SAlex Richardson HIDDEN float
55*31914882SAlex Richardson __math_divzerof (uint32_t sign)
56*31914882SAlex Richardson {
57*31914882SAlex Richardson   float y = opt_barrier_float (sign ? -1.0f : 1.0f) / 0.0f;
58*31914882SAlex Richardson   return with_errnof (y, ERANGE);
59*31914882SAlex Richardson }
60*31914882SAlex Richardson 
61*31914882SAlex Richardson HIDDEN float
62*31914882SAlex Richardson __math_invalidf (float x)
63*31914882SAlex Richardson {
64*31914882SAlex Richardson   float y = (x - x) / (x - x);
65*31914882SAlex Richardson   return isnan (x) ? y : with_errnof (y, EDOM);
66*31914882SAlex Richardson }
67*31914882SAlex Richardson 
68*31914882SAlex Richardson /* Check result and set errno if necessary.  */
69*31914882SAlex Richardson 
70*31914882SAlex Richardson HIDDEN float
71*31914882SAlex Richardson __math_check_uflowf (float y)
72*31914882SAlex Richardson {
73*31914882SAlex Richardson   return y == 0.0f ? with_errnof (y, ERANGE) : y;
74*31914882SAlex Richardson }
75*31914882SAlex Richardson 
76*31914882SAlex Richardson HIDDEN float
77*31914882SAlex Richardson __math_check_oflowf (float y)
78*31914882SAlex Richardson {
79*31914882SAlex Richardson   return isinf (y) ? with_errnof (y, ERANGE) : y;
80*31914882SAlex Richardson }
81