xref: /freebsd/contrib/arm-optimized-routines/math/math_err.c (revision 31914882fca502069810b9e9ddea4bcd8136a4f4)
1*31914882SAlex Richardson /*
2*31914882SAlex Richardson  * Double-precision math error handling.
3*31914882SAlex Richardson  *
4*31914882SAlex Richardson  * Copyright (c) 2018, 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 double
15*31914882SAlex Richardson with_errno (double 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_errno(x, e) (x)
22*31914882SAlex Richardson #endif
23*31914882SAlex Richardson 
24*31914882SAlex Richardson /* NOINLINE reduces code size.  */
25*31914882SAlex Richardson NOINLINE static double
26*31914882SAlex Richardson xflow (uint32_t sign, double y)
27*31914882SAlex Richardson {
28*31914882SAlex Richardson   y = eval_as_double (opt_barrier_double (sign ? -y : y) * y);
29*31914882SAlex Richardson   return with_errno (y, ERANGE);
30*31914882SAlex Richardson }
31*31914882SAlex Richardson 
32*31914882SAlex Richardson HIDDEN double
33*31914882SAlex Richardson __math_uflow (uint32_t sign)
34*31914882SAlex Richardson {
35*31914882SAlex Richardson   return xflow (sign, 0x1p-767);
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 double
42*31914882SAlex Richardson __math_may_uflow (uint32_t sign)
43*31914882SAlex Richardson {
44*31914882SAlex Richardson   return xflow (sign, 0x1.8p-538);
45*31914882SAlex Richardson }
46*31914882SAlex Richardson #endif
47*31914882SAlex Richardson 
48*31914882SAlex Richardson HIDDEN double
49*31914882SAlex Richardson __math_oflow (uint32_t sign)
50*31914882SAlex Richardson {
51*31914882SAlex Richardson   return xflow (sign, 0x1p769);
52*31914882SAlex Richardson }
53*31914882SAlex Richardson 
54*31914882SAlex Richardson HIDDEN double
55*31914882SAlex Richardson __math_divzero (uint32_t sign)
56*31914882SAlex Richardson {
57*31914882SAlex Richardson   double y = opt_barrier_double (sign ? -1.0 : 1.0) / 0.0;
58*31914882SAlex Richardson   return with_errno (y, ERANGE);
59*31914882SAlex Richardson }
60*31914882SAlex Richardson 
61*31914882SAlex Richardson HIDDEN double
62*31914882SAlex Richardson __math_invalid (double x)
63*31914882SAlex Richardson {
64*31914882SAlex Richardson   double y = (x - x) / (x - x);
65*31914882SAlex Richardson   return isnan (x) ? y : with_errno (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 double
71*31914882SAlex Richardson __math_check_uflow (double y)
72*31914882SAlex Richardson {
73*31914882SAlex Richardson   return y == 0.0 ? with_errno (y, ERANGE) : y;
74*31914882SAlex Richardson }
75*31914882SAlex Richardson 
76*31914882SAlex Richardson HIDDEN double
77*31914882SAlex Richardson __math_check_oflow (double y)
78*31914882SAlex Richardson {
79*31914882SAlex Richardson   return isinf (y) ? with_errno (y, ERANGE) : y;
80*31914882SAlex Richardson }
81