2012-03-23 Daniel Jacobowitz <dmj@google.com>
[platform/upstream/linaro-glibc.git] / math / s_cexpl.c
1 /* Return value of complex exponential function for long double complex value.
2    Copyright (C) 1997-2012 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <complex.h>
21 #include <fenv.h>
22 #include <math.h>
23 #include <math_private.h>
24 #include <float.h>
25
26 __complex__ long double
27 __cexpl (__complex__ long double x)
28 {
29   __complex__ long double retval;
30   int rcls = fpclassify (__real__ x);
31   int icls = fpclassify (__imag__ x);
32
33   if (__builtin_expect (rcls >= FP_ZERO, 1))
34     {
35       /* Real part is finite.  */
36       if (__builtin_expect (icls >= FP_ZERO, 1))
37         {
38           /* Imaginary part is finite.  */
39           const int t = (int) ((LDBL_MAX_EXP - 1) * M_LN2l);
40           long double sinix, cosix;
41
42           __sincosl (__imag__ x, &sinix, &cosix);
43
44           if (__real__ x > t)
45             {
46               long double exp_t = __ieee754_expl (t);
47               __real__ x -= t;
48               sinix *= exp_t;
49               cosix *= exp_t;
50               if (__real__ x > t)
51                 {
52                   __real__ x -= t;
53                   sinix *= exp_t;
54                   cosix *= exp_t;
55                 }
56             }
57           if (__real__ x > t)
58             {
59               /* Overflow (original real part of x > 3t).  */
60               __real__ retval = LDBL_MAX * cosix;
61               __imag__ retval = LDBL_MAX * sinix;
62             }
63           else
64             {
65               long double exp_val = __ieee754_expl (__real__ x);
66               __real__ retval = exp_val * cosix;
67               __imag__ retval = exp_val * sinix;
68             }
69         }
70       else
71         {
72           /* If the imaginary part is +-inf or NaN and the real part
73              is not +-inf the result is NaN + iNaN.  */
74           __real__ retval = __nanl ("");
75           __imag__ retval = __nanl ("");
76
77           feraiseexcept (FE_INVALID);
78         }
79     }
80   else if (__builtin_expect (rcls == FP_INFINITE, 1))
81     {
82       /* Real part is infinite.  */
83       if (__builtin_expect (icls >= FP_ZERO, 1))
84         {
85           /* Imaginary part is finite.  */
86           long double value = signbit (__real__ x) ? 0.0 : HUGE_VALL;
87
88           if (icls == FP_ZERO)
89             {
90               /* Imaginary part is 0.0.  */
91               __real__ retval = value;
92               __imag__ retval = __imag__ x;
93             }
94           else
95             {
96               long double sinix, cosix;
97
98               __sincosl (__imag__ x, &sinix, &cosix);
99
100               __real__ retval = __copysignl (value, cosix);
101               __imag__ retval = __copysignl (value, sinix);
102             }
103         }
104       else if (signbit (__real__ x) == 0)
105         {
106           __real__ retval = HUGE_VALL;
107           __imag__ retval = __nanl ("");
108
109           if (icls == FP_INFINITE)
110             feraiseexcept (FE_INVALID);
111         }
112       else
113         {
114           __real__ retval = 0.0;
115           __imag__ retval = __copysignl (0.0, __imag__ x);
116         }
117     }
118   else
119     {
120       /* If the real part is NaN the result is NaN + iNaN.  */
121       __real__ retval = __nanl ("");
122       __imag__ retval = __nanl ("");
123
124       if (rcls != FP_NAN || icls != FP_NAN)
125         feraiseexcept (FE_INVALID);
126     }
127
128   return retval;
129 }
130 weak_alias (__cexpl, cexpl)