/ src / ref / tanpi.c
tanpi.c
  1  /*
  2   * Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without modification,
  5   * are permitted provided that the following conditions are met:
  6   * 1. Redistributions of source code must retain the above copyright notice,
  7   *    this list of conditions and the following disclaimer.
  8   * 2. Redistributions in binary form must reproduce the above copyright notice,
  9   *    this list of conditions and the following disclaimer in the documentation
 10   *    and/or other materials provided with the distribution.
 11   * 3. Neither the name of the copyright holder nor the names of its contributors
 12   *    may be used to endorse or promote products derived from this software without
 13   *    specific prior written permission.
 14   *
 15   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 16   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 17   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 18   * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 19   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 20   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 21   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 22   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 24   * POSSIBILITY OF SUCH DAMAGE.
 25   *
 26   */
 27  
 28  #include "libm_amd.h"
 29  #include "libm_util_amd.h"
 30  #include "libm_inlines_amd.h"
 31  #include "libm_special.h"
 32  
 33  
 34  // tan(x + xx) approximation valid on the interval [-pi/4,pi/4].
 35  // If recip is true return -1/tan(x + xx) instead.
 36  static inline double tan_piby4(double x, double xx, int recip)
 37  {
 38    double r, t1, t2, xl;
 39    int transform = 0;
 40    static const double
 41       piby4_lead = 7.85398163397448278999e-01, /* 0x3fe921fb54442d18 */
 42       piby4_tail = 3.06161699786838240164e-17; /* 0x3c81a62633145c06 */
 43  
 44    /* In order to maintain relative precision transform using the identity:
 45       tan(pi/4-x) = (1-tan(x))/(1+tan(x)) for arguments close to pi/4.
 46       Similarly use tan(x-pi/4) = (tan(x)-1)/(tan(x)+1) close to -pi/4. */
 47  
 48    if (x > 0.68)
 49      {
 50        transform = 1;
 51        x = piby4_lead - x;
 52        xl = piby4_tail - xx;
 53        x += xl;
 54        xx = 0.0;
 55      }
 56    else if (x < -0.68)
 57      {
 58        transform = -1;
 59        x = piby4_lead + x;
 60        xl = piby4_tail + xx;
 61        x += xl;
 62        xx = 0.0;
 63      }
 64  
 65    /* Core Remez [2,3] approximation to tan(x+xx) on the
 66       interval [0,0.68]. */
 67  
 68    r = x*x + 2.0 * x * xx;
 69    t1 = x;
 70    t2 = xx + x*r*
 71      (0.372379159759792203640806338901e0 +
 72       (-0.229345080057565662883358588111e-1 +
 73        0.224044448537022097264602535574e-3*r)*r)/
 74      (0.111713747927937668539901657944e1 +
 75       (-0.515658515729031149329237816945e0 +
 76        (0.260656620398645407524064091208e-1 -
 77         0.232371494088563558304549252913e-3*r)*r)*r);
 78  
 79    /* Reconstruct tan(x) in the transformed case. */
 80  
 81    if (transform)
 82      {
 83        double t;
 84        t = t1 + t2;
 85        if (recip)
 86           return transform*(2*t/(t-1) - 1.0);
 87        else
 88           return transform*(1.0 - 2*t/(1+t));
 89      }
 90  
 91    if (recip)
 92      {
 93        /* Compute -1.0/(t1 + t2) accurately */
 94        double trec, trec_top, z1, z2, t;
 95        unsigned long long u;
 96        t = t1 + t2;
 97        GET_BITS_DP64(t, u);
 98        u &= 0xffffffff00000000;
 99        PUT_BITS_DP64(u, z1);
100        z2 = t2 - (z1 - t1);
101        trec = -1.0 / t;
102        GET_BITS_DP64(trec, u);
103        u &= 0xffffffff00000000;
104        PUT_BITS_DP64(u, trec_top);
105        return trec_top + trec * ((1.0 + trec_top * z1) + trec_top * z2);
106  
107      }
108    else
109      return t1 + t2;
110  }
111  
112  
113  
114  double FN_PROTOTYPE_REF(tanpi)(double x)
115  {
116      double r, dx, xsgn, xodd;
117      long long ux;
118      const double pi = 3.1415926535897932384626433832795;
119  
120      xsgn = x > 0.0 ? 1.0 : -1.0;
121      GET_BITS_DP64(x, ux);
122      ux = ux & ~SIGNBIT_DP64;
123  
124      // Handle +-Inf and NaN
125      if (ux >= PINFBITPATT_DP64)
126      {
127  		PUT_BITS_DP64(INDEFBITPATT_DP64,x);
128  		return x;
129  	}
130  
131      // If x >= 2^53, it is an even integer
132      if (ux > 0x433fffffffffffffL)
133  	return xsgn * 0.0;
134  
135      // If x >= 2^52, it is an integer
136      // Given the previous test, we also know that the last bits of ux are the
137      // same as the last bits of (long)ux
138      if (ux > 0x432fffffffffffffL)
139  	return xsgn * (ux & 0x1L ? -0.0 : 0.0);
140  
141      dx = x * xsgn;
142  
143      GET_BITS_DP64(dx, ux);
144      // Take care of small arguments
145      if (dx <= 0.25) {
146          if (ux < 0x3f10000000000000) {
147  	    if (ux < 0x3e40000000000000)
148  		return x * pi;
149  	    dx = x * pi;
150  	    return dx + dx*dx*dx*(1.0 / 3.0);
151  	}
152  	return tan_piby4(x*pi, 0.0, 0);
153      }
154  
155      ux = (long)dx;
156      r = dx - (double)ux;
157      xodd = xsgn * (ux & 0x1 ? -1.0 : 1.0);
158  
159      if (r == 0.0)
160  	return xodd * 0.0;
161  
162      if (r <= 0.25)
163  	return xsgn * tan_piby4(r*pi, 0.0, 0);
164  
165      if (r < 0.5)
166  	return -xsgn * tan_piby4((0.5 - r)*pi, 0.0, 1);
167  
168      if (r == 0.5)
169      {
170  		PUT_BITS_DP64(PINFBITPATT_DP64,x);
171  		return xodd * x;
172  	}
173  
174      if (r <= 0.75)
175  	return xsgn * tan_piby4((r - 0.5)*pi, 0.0, 1);
176  
177      // r < 1
178      return -xsgn * tan_piby4((1.0 - r)*pi, 0.0, 0);
179  }
180  
181  
182  
183