Update to 4.8.2.
[platform/upstream/gcc48.git] / libquadmath / math / cexpq.c
1 /* Return value of complex exponential function for complex __float128 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 "quadmath-imp.h"
21
22 #ifdef HAVE_FENV_H
23 # include <fenv.h>
24 #endif
25
26
27 __complex128
28 cexpq (__complex128 x)
29 {
30   __complex128 retval;
31   int rcls = fpclassifyq (__real__ x);
32   int icls = fpclassifyq (__imag__ x);
33
34   if (__builtin_expect (rcls >= QUADFP_ZERO, 1))
35     {
36       /* Real part is finite.  */
37       if (__builtin_expect (icls >= QUADFP_ZERO, 1))
38         {
39           /* Imaginary part is finite.  */
40           const int t = (int) ((FLT128_MAX_EXP - 1) * M_LN2q);
41           __float128 sinix, cosix;
42
43           if (__builtin_expect (icls != QUADFP_SUBNORMAL, 1))
44             {
45               sincosq (__imag__ x, &sinix, &cosix);
46             }
47           else
48             {
49               sinix = __imag__ x;
50               cosix = 1.0Q;
51             }
52
53           if (__real__ x > t)
54             {
55               __float128 exp_t = expq (t);
56               __real__ x -= t;
57               sinix *= exp_t;
58               cosix *= exp_t;
59               if (__real__ x > t)
60                 {
61                   __real__ x -= t;
62                   sinix *= exp_t;
63                   cosix *= exp_t;
64                 }
65             }
66           if (__real__ x > t)
67             {
68               /* Overflow (original real part of x > 3t).  */
69               __real__ retval = FLT128_MAX * cosix;
70               __imag__ retval = FLT128_MAX * sinix;
71             }
72           else
73             {
74               __float128 exp_val = expq (__real__ x);
75               __real__ retval = exp_val * cosix;
76               __imag__ retval = exp_val * sinix;
77             }
78         }
79       else
80         {
81           /* If the imaginary part is +-inf or NaN and the real part
82              is not +-inf the result is NaN + iNaN.  */
83           __real__ retval = nanq ("");
84           __imag__ retval = nanq ("");
85
86 #ifdef HAVE_FENV_H
87           feraiseexcept (FE_INVALID);
88 #endif
89         }
90     }
91   else if (__builtin_expect (rcls == QUADFP_INFINITE, 1))
92     {
93       /* Real part is infinite.  */
94       if (__builtin_expect (icls >= QUADFP_ZERO, 1))
95         {
96           /* Imaginary part is finite.  */
97           __float128 value = signbitq (__real__ x) ? 0.0Q : HUGE_VALQ;
98
99           if (icls == QUADFP_ZERO)
100             {
101               /* Imaginary part is 0.0.  */
102               __real__ retval = value;
103               __imag__ retval = __imag__ x;
104             }
105           else
106             {
107               __float128 sinix, cosix;
108
109               if (__builtin_expect (icls != QUADFP_SUBNORMAL, 1))
110                 {
111                   sincosq (__imag__ x, &sinix, &cosix);
112                 }
113               else
114                 {
115                   sinix = __imag__ x;
116                   cosix = 1.0Q;
117                 }
118
119               __real__ retval = copysignq (value, cosix);
120               __imag__ retval = copysignq (value, sinix);
121             }
122         }
123       else if (signbitq (__real__ x) == 0)
124         {
125           __real__ retval = HUGE_VALQ;
126           __imag__ retval = nanq ("");
127
128 #ifdef HAVE_FENV_H
129           if (icls == QUADFP_INFINITE)
130             feraiseexcept (FE_INVALID);
131 #endif
132         }
133       else
134         {
135           __real__ retval = 0.0Q;
136           __imag__ retval = copysignq (0.0Q, __imag__ x);
137         }
138     }
139   else
140     {
141       /* If the real part is NaN the result is NaN + iNaN.  */
142       __real__ retval = nanq ("");
143       __imag__ retval = nanq ("");
144
145 #ifdef HAVE_FENV_H
146       if (rcls != QUADFP_NAN || icls != QUADFP_NAN)
147         feraiseexcept (FE_INVALID);
148 #endif
149     }
150
151   return retval;
152 }