/ src / fast / tanf.c
tanf.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_macros.h>
 29  #include <libm_special.h>
 30  #include <libm/amd_funcs_internal.h>
 31  #include <libm/types.h>
 32  #include <libm/constants.h>
 33  #include <libm/typehelper.h>
 34  #include <libm/compiler.h>
 35  #include <libm/poly.h>
 36  
 37  /*
 38   * ISO-IEC-10967-2: Elementary Numerical Functions
 39   * Signature:
 40   *   float tanf(float x)
 41   *
 42   * Spec:
 43   *   tanf(n· 2π + π/4)  = 1       if n∈Z and |n· 2π + π/4|   <= big_angle_F
 44   *   tanf(n· 2π + 3π/4) = −1      if n∈Z and |n· 2π + 3π/4|  <= big angle rF
 45   *   tanf(x) = x                  if x ∈ F^(2·π) and tanf(x) != tan(x)
 46   *                                               and |x| < sqrt(epsilonF/rF)
 47   *   tanf(−x) = −tanf(x)          if x ∈ F^(2·π)
 48   */
 49  
 50  static struct {
 51      float poly_tanf[7];
 52      float halfpi, invhalfpi;
 53      float huge;
 54      float halfpi1, halfpi2, halfpi3;
 55  } tanf_data = {
 56      .huge      = 0x1.8p23,
 57      .halfpi    = 0x1.921fb6p0,
 58      .invhalfpi = 0x1.45f306p-1,
 59      .halfpi1   = -0x1.921fb6p0,
 60      .halfpi2   = 0x1.777a5cp-25,
 61      .halfpi3   = 0x1.ee59dap-50,
 62      /*
 63       * Polynomial coefficients obtained using
 64       * fpminimax algorithm from Sollya
 65       */
 66      .poly_tanf = {
 67          0x1.555566p-2,
 68          0x1.110cdp-3,
 69          0x1.baf34p-5,
 70          0x1.5bf38ep-6,
 71          0x1.663acap-7,
 72          -0x1.07c6f4p-16,
 73          0x1.21cedap-8,
 74      },
 75  };
 76  
 77  #define  ALM_TANF_HUGE      tanf_data.huge
 78  #define  ALM_TANF_HALFPI    tanf_data.halfpi
 79  #define  ALM_TANF_INVHALFPI tanf_data.invhalfpi
 80  
 81  #define  ALM_TANF_HALFPI1 tanf_data.halfpi1
 82  #define  ALM_TANF_HALFPI2 tanf_data.halfpi2
 83  #define  ALM_TANF_HALFPI3 tanf_data.halfpi3
 84  
 85  #define  ALM_TANF_SIGN_MASK32 (1U<<31)
 86  
 87  #define C1 tanf_data.poly_tanf[0]
 88  #define C2 tanf_data.poly_tanf[1]
 89  #define C3 tanf_data.poly_tanf[2]
 90  #define C4 tanf_data.poly_tanf[3]
 91  #define C5 tanf_data.poly_tanf[4]
 92  #define C6 tanf_data.poly_tanf[5]
 93  #define C7 tanf_data.poly_tanf[6]
 94  
 95  
 96  /*
 97   * Implementation Notes:
 98   *  Convert given x into the form
 99   *
100   *        |x| = N*(pi/2)+f
101   *                        where N is integer and f in [-pi/4,+pi/4]
102   *
103   *             N = round(|x|*2/pi)
104   *             f = |x| - N * pi/2
105   *
106   * tan(x) = tan(f)                when N is even
107   *        = -cot(f) = -1/tan(f) when N is odd
108   *
109   * The term tan(f) can be approximated by using a polynomial
110   */
111  
112  float
113  ALM_PROTO_FAST(tanf)(float x)
114  {
115      float      F, poly, result = 0.0;
116      uint32_t   sign, n;
117      uint32_t   ux = asuint32(x);
118  
119      if (ux == 0)
120          return 0.0f;
121  
122      sign = ux & (ALM_TANF_SIGN_MASK32);
123  
124      /* x = abs(x) */
125      x    = asfloat(ux & ~ALM_TANF_SIGN_MASK32);
126  
127      /*
128       * dn = x * (2/π)
129       * would turn to fma
130       */
131      float nn =  x * ALM_TANF_INVHALFPI + ALM_TANF_HUGE;
132  
133      /* n = (int)n */
134      n  = asuint32(nn);
135  
136      nn -= ALM_TANF_HUGE;
137  
138      /* F = xd - (n * π/2)
139       * F = n*halfpi1+x ;
140       * F = n*halfpi2+F ;
141       * F = n*halfpi3+F ;
142       */
143      F = x + nn * ALM_TANF_HALFPI1;
144      F = F + nn * ALM_TANF_HALFPI2;
145      F = F + nn * ALM_TANF_HALFPI3;
146  
147      uint32_t odd = (n & 0x1);
148  
149      // Calculate the polynomial approximation
150      //  = x+C1*x^3+C2*x^5+C3*x^7+C4*x^9+C5*x^11+C6*x^13+C7*x^15
151      poly   = POLY_EVAL_ODD_15(F, C1, C2, C3, C4, C5, C6, C7);
152  
153      result = asfloat(sign ^ asuint32(poly));
154  
155      if (odd)
156          result = -1.0/result;
157  
158      return result;
159  }