1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  23  */
  24 /*
  25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29 #pragma weak catanf = __catanf
  30 
  31 #include "libm.h"
  32 #include "complex_wrapper.h"
  33 
  34 #if defined(__i386) && !defined(__amd64)
  35 extern int __swapRP(int);
  36 #endif
  37 
  38 static const float
  39         pi_2 = 1.570796326794896558e+00F,
  40         zero = 0.0F,
  41         half = 0.5F,
  42         two = 2.0F,
  43         one = 1.0F;
  44 
  45 fcomplex
  46 catanf(fcomplex z) {
  47         fcomplex        ans;
  48         float           x, y, ax, ay, t;
  49         double          dx, dy, dt;
  50         int             hx, hy, ix, iy;
  51 
  52         x = F_RE(z);
  53         y = F_IM(z);
  54         ax = fabsf(x);
  55         ay = fabsf(y);
  56         hx = THE_WORD(x);
  57         hy = THE_WORD(y);
  58         ix = hx & 0x7fffffff;
  59         iy = hy & 0x7fffffff;
  60 
  61         if (ix >= 0x7f800000) {              /* x is inf or NaN */
  62                 if (ix == 0x7f800000) {
  63                         F_RE(ans) = pi_2;
  64                         F_IM(ans) = zero;
  65                 } else {
  66                         F_RE(ans) = x * x;
  67                         if (iy == 0 || iy == 0x7f800000)
  68                                 F_IM(ans) = zero;
  69                         else
  70                                 F_IM(ans) = (fabsf(y) - ay) / (fabsf(y) - ay);
  71                 }
  72         } else if (iy >= 0x7f800000) {       /* y is inf or NaN */
  73                 if (iy == 0x7f800000) {
  74                         F_RE(ans) = pi_2;
  75                         F_IM(ans) = zero;
  76                 } else {
  77                         F_RE(ans) = (fabsf(x) - ax) / (fabsf(x) - ax);
  78                         F_IM(ans) = y * y;
  79                 }
  80         } else if (ix == 0) {
  81                 /* INDENT OFF */
  82                 /*
  83                  * x = 0
  84                  *      1                            1
  85                  * A = --- * atan2(2x, 1-x*x-y*y) = --- atan2(0,1-|y|)
  86                  *      2                            2
  87                  *
  88                  *     1     [ (y+1)*(y+1) ]   1          2      1         2y
  89                  * B = - log [ ----------- ] = - log (1+ ---) or - log(1+ ----)
  90                  *     4     [ (y-1)*(y-1) ]   2         y-1     2         1-y
  91                  */
  92                 /* INDENT ON */
  93                 t = one - ay;
  94                 if (iy == 0x3f800000) {
  95                         /* y=1: catan(0,1)=(0,+inf) with 1/0 signal */
  96                         F_IM(ans) = ay / ax;
  97                         F_RE(ans) = zero;
  98                 } else if (iy > 0x3f800000) {        /* y>1 */
  99                         F_IM(ans) = half * log1pf(two / (-t));
 100                         F_RE(ans) = pi_2;
 101                 } else {                /* y<1 */
 102                         F_IM(ans) = half * log1pf((ay + ay) / t);
 103                         F_RE(ans) = zero;
 104                 }
 105         } else {
 106                 /* INDENT OFF */
 107                 /*
 108                  * use double precision x,y
 109                  *      1
 110                  * A = --- * atan2(2x, 1-x*x-y*y)
 111                  *      2
 112                  *
 113                  *     1     [ x*x+(y+1)*(y+1) ]   1               4y
 114                  * B = - log [ --------------- ] = - log (1+ -----------------)
 115                  *     4     [ x*x+(y-1)*(y-1) ]   4         x*x + (y-1)*(y-1)
 116                  */
 117                 /* INDENT ON */
 118 #if defined(__i386) && !defined(__amd64)
 119                 int     rp = __swapRP(fp_extended);
 120 #endif
 121                 dx = (double)ax;
 122                 dy = (double)ay;
 123                 F_RE(ans) = (float)(0.5 * atan2(dx + dx,
 124                     1.0 - dx * dx - dy * dy));
 125                 dt = dy - 1.0;
 126                 F_IM(ans) = (float)(0.25 * log1p(4.0 * dy /
 127                     (dx * dx + dt * dt)));
 128 #if defined(__i386) && !defined(__amd64)
 129                 if (rp != fp_extended)
 130                         (void) __swapRP(rp);
 131 #endif
 132         }
 133         if (hx < 0)
 134                 F_RE(ans) = -F_RE(ans);
 135         if (hy < 0)
 136                 F_IM(ans) = -F_IM(ans);
 137         return (ans);
 138 }