Home | History | Annotate | Line # | Download | only in math
      1 /* Complex tangent function for a complex float type.
      2    Copyright (C) 1997-2018 Free Software Foundation, Inc.
      3    This file is part of the GNU C Library.
      4    Contributed by Ulrich Drepper <drepper (at) 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 __complex128
     23 ctanq (__complex128 x)
     24 {
     25   __complex128 res;
     26 
     27   if (__glibc_unlikely (!finiteq (__real__ x) || !finiteq (__imag__ x)))
     28     {
     29       if (isinfq (__imag__ x))
     30 	{
     31 	  if (finiteq (__real__ x) && fabsq (__real__ x) > 1)
     32 	    {
     33 	      __float128 sinrx, cosrx;
     34 	      sincosq (__real__ x, &sinrx, &cosrx);
     35 	      __real__ res = copysignq (0, sinrx * cosrx);
     36 	    }
     37 	  else
     38 	    __real__ res = copysignq (0, __real__ x);
     39 	  __imag__ res = copysignq (1, __imag__ x);
     40 	}
     41       else if (__real__ x == 0)
     42 	{
     43 	  res = x;
     44 	}
     45       else
     46 	{
     47 	  __real__ res = nanq ("");
     48 	  if (__imag__ x == 0)
     49 	    __imag__ res = __imag__ x;
     50 	  else
     51 	    __imag__ res = nanq ("");
     52 
     53 	  if (isinfq (__real__ x))
     54 	    feraiseexcept (FE_INVALID);
     55 	}
     56     }
     57   else
     58     {
     59       __float128 sinrx, cosrx;
     60       __float128 den;
     61       const int t = (int) ((FLT128_MAX_EXP - 1) * M_LN2q / 2);
     62 
     63       /* tan(x+iy) = (sin(2x) + i*sinh(2y))/(cos(2x) + cosh(2y))
     64 	 = (sin(x)*cos(x) + i*sinh(y)*cosh(y)/(cos(x)^2 + sinh(y)^2). */
     65 
     66       if (__glibc_likely (fabsq (__real__ x) > FLT128_MIN))
     67 	{
     68 	  sincosq (__real__ x, &sinrx, &cosrx);
     69 	}
     70       else
     71 	{
     72 	  sinrx = __real__ x;
     73 	  cosrx = 1;
     74 	}
     75 
     76       if (fabsq (__imag__ x) > t)
     77 	{
     78 	  /* Avoid intermediate overflow when the real part of the
     79 	     result may be subnormal.  Ignoring negligible terms, the
     80 	     imaginary part is +/- 1, the real part is
     81 	     sin(x)*cos(x)/sinh(y)^2 = 4*sin(x)*cos(x)/exp(2y).  */
     82 	  __float128 exp_2t = expq (2 * t);
     83 
     84 	  __imag__ res = copysignq (1, __imag__ x);
     85 	  __real__ res = 4 * sinrx * cosrx;
     86 	  __imag__ x = fabsq (__imag__ x);
     87 	  __imag__ x -= t;
     88 	  __real__ res /= exp_2t;
     89 	  if (__imag__ x > t)
     90 	    {
     91 	      /* Underflow (original imaginary part of x has absolute
     92 		 value > 2t).  */
     93 	      __real__ res /= exp_2t;
     94 	    }
     95 	  else
     96 	    __real__ res /= expq (2 * __imag__ x);
     97 	}
     98       else
     99 	{
    100 	  __float128 sinhix, coshix;
    101 	  if (fabsq (__imag__ x) > FLT128_MIN)
    102 	    {
    103 	      sinhix = sinhq (__imag__ x);
    104 	      coshix = coshq (__imag__ x);
    105 	    }
    106 	  else
    107 	    {
    108 	      sinhix = __imag__ x;
    109 	      coshix = 1;
    110 	    }
    111 
    112 	  if (fabsq (sinhix) > fabsq (cosrx) * FLT128_EPSILON)
    113 	    den = cosrx * cosrx + sinhix * sinhix;
    114 	  else
    115 	    den = cosrx * cosrx;
    116 	  __real__ res = sinrx * cosrx / den;
    117 	  __imag__ res = sinhix * coshix / den;
    118 	}
    119       math_check_force_underflow_complex (res);
    120     }
    121 
    122   return res;
    123 }
    124