1 | /* Implement __kernel_standard_l. |
2 | Copyright (C) 2012-2018 Free Software Foundation, Inc. |
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 |
17 | <http://www.gnu.org/licenses/>. |
18 | |
19 | Parts based on k_standard.c from fdlibm: */ |
20 | |
21 | /* @(#)k_standard.c 5.1 93/09/24 */ |
22 | /* |
23 | * ==================================================== |
24 | * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
25 | * |
26 | * Developed at SunPro, a Sun Microsystems, Inc. business. |
27 | * Permission to use, copy, modify, and distribute this |
28 | * software is freely granted, provided that this notice |
29 | * is preserved. |
30 | * ==================================================== |
31 | */ |
32 | |
33 | #include <math.h> |
34 | #include <math-barriers.h> |
35 | #include <math_private.h> |
36 | #include <math-svid-compat.h> |
37 | #include <fenv.h> |
38 | #include <float.h> |
39 | #include <errno.h> |
40 | |
41 | |
42 | #if LIBM_SVID_COMPAT |
43 | |
44 | static double zero = 0.0; |
45 | |
46 | /* Handle errors for a libm function as specified by TYPE (see |
47 | comments in k_standard.c for details), with arguments X and Y, |
48 | returning the appropriate return value for that function. */ |
49 | |
50 | long double |
51 | __kernel_standard_l (long double x, long double y, int type) |
52 | { |
53 | double dx, dy; |
54 | struct exception exc; |
55 | fenv_t env; |
56 | |
57 | feholdexcept (&env); |
58 | dx = x; |
59 | dy = y; |
60 | math_force_eval (dx); |
61 | math_force_eval (dy); |
62 | fesetenv (&env); |
63 | |
64 | switch (type) |
65 | { |
66 | case 221: |
67 | /* powl (x, y) overflow. */ |
68 | exc.arg1 = dx; |
69 | exc.arg2 = dy; |
70 | exc.type = OVERFLOW; |
71 | exc.name = (char *) "powl" ; |
72 | if (_LIB_VERSION == _SVID_) |
73 | { |
74 | exc.retval = HUGE; |
75 | y *= 0.5; |
76 | if (x < zero && __rintl (y) != y) |
77 | exc.retval = -HUGE; |
78 | } |
79 | else |
80 | { |
81 | exc.retval = HUGE_VAL; |
82 | y *= 0.5; |
83 | if (x < zero && __rintl (y) != y) |
84 | exc.retval = -HUGE_VAL; |
85 | } |
86 | if (_LIB_VERSION == _POSIX_) |
87 | __set_errno (ERANGE); |
88 | else if (!matherr (&exc)) |
89 | __set_errno (ERANGE); |
90 | return exc.retval; |
91 | |
92 | case 222: |
93 | /* powl (x, y) underflow. */ |
94 | exc.arg1 = dx; |
95 | exc.arg2 = dy; |
96 | exc.type = UNDERFLOW; |
97 | exc.name = (char *) "powl" ; |
98 | exc.retval = zero; |
99 | y *= 0.5; |
100 | if (x < zero && __rintl (y) != y) |
101 | exc.retval = -zero; |
102 | if (_LIB_VERSION == _POSIX_) |
103 | __set_errno (ERANGE); |
104 | else if (!matherr (&exc)) |
105 | __set_errno (ERANGE); |
106 | return exc.retval; |
107 | |
108 | default: |
109 | return __kernel_standard (dx, dy, type); |
110 | } |
111 | } |
112 | #endif |
113 | |