/ src / fast / logf.c
logf.c
  1  /*
  2   * Copyright (C) 2019, Advanced Micro Devices. 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  #include <stdint.h>
 28  #include <libm_util_amd.h>
 29  #include <libm_special.h>
 30  
 31  #include <libm_macros.h>
 32  #include <libm/amd_funcs_internal.h>
 33  #include <libm/types.h>
 34  #include <libm/typehelper.h>
 35  #include <libm/compiler.h>
 36  #include <libm/poly.h>
 37  
 38  static struct {
 39      float poly[9];
 40      float ln2;
 41  } logf_data = {
 42      .ln2 = 0x1.62e42fefp-1f,
 43      // Polynomial coefficients obtained using fpminimax algorithm from Sollya
 44      .poly = {
 45          0x1.0000000f500p0f,
 46          -0x1.ffffd272p-2f,
 47          0x1.5554e6dap-2f,
 48          -0x1.00150b01p-2f,
 49          0x1.99d8391ap-3f,
 50          -0x1.50224b33p-3f,
 51          0x1.1e779278p-3f,
 52          -0x1.3b751efcp-3f,
 53          0x1.1fde870dp-3f,
 54      },
 55  };
 56  
 57  #define ln2 logf_data.ln2
 58  #define C1 logf_data.poly[0]
 59  #define C2 logf_data.poly[1]
 60  #define C3 logf_data.poly[2]
 61  #define C4 logf_data.poly[3]
 62  #define C5 logf_data.poly[4]
 63  #define C6 logf_data.poly[5]
 64  #define C7 logf_data.poly[6]
 65  #define C8 logf_data.poly[7]
 66  #define C9 logf_data.poly[8]
 67  
 68  
 69  /*
 70   * Implementation Notes:
 71   *     reduce 'x' into the form:
 72   *        x = (-1)^s*2^n*m
 73   * 's' will be always zero, as log is defined for posititve numbers
 74   * 'n' is an integer known as the exponent
 75   * 'm' is mantissa
 76   *
 77   * x is reduced such that the mantissa, m lies in [2/3,4/3]
 78   *      x = 2^n*m where m is in [2/3,4/3]
 79   *      log(x) = log(2^n*m)         We have log(a*b) = log(a)+log(b)
 80   *             = log(2^n) + log(m)   We have log(a^n) = n*log(a)
 81   *             = n*log(2) + log(m)
 82   *             = n*log(2) + log(1+(m-1))
 83   *             = n*log(2) + log(1+f)        Where f = m-1
 84   *             = n*log(2) + log1p(f)        f lies in [-1/3,+1/3]
 85   *
 86   * Thus we have :
 87   * log(x) = n*log(2) + log1p(f)
 88   *            log1p(F) is approximated by using a polynomial
 89   */
 90  
 91  float
 92  FN_PROTOTYPE_FAST(logf)(float x)
 93  {
 94      float m, r, n, f;
 95  
 96      // 0 and FLT_MAX
 97      if ((x > 0.0f) && (x <= 0x1.fffffep+127)) {
 98          // Get the exponent
 99          int32_t ux = (asuint32(x) - 0x3f2aaaab) & 0xff800000;
100          n = (float)(ux >> EXPSHIFTBITS_SP32) ;
101          // Get the mantissa, m is in [2/3, 4/3]
102          m = asfloat(asuint32(x) - ux);
103  
104          f = m - 1.0f;// f is in [-1/3,+1/3]
105  
106          // Compute log1p(f) using Polynomial approximation
107          r = POLY_EVAL_9(f, C1, C2, C3, C4, C5, C6, C7, C8, C9);
108  
109          r = n*ln2 + r;
110  
111      } else {
112          r = x + x;  // Output NaNs for the inputs NaN's
113          if (x  < 0.0f) r =  0.0f / 0.0f; //  NaN
114          if (x == 0.0f) r = -1.0f / 0.0f; // -Inf
115      }
116  
117      return r;
118  
119  }
120  
121  strong_alias (__logf_finite, FN_PROTOTYPE_FAST(logf))
122  weak_alias (logf, FN_PROTOTYPE_FAST(logf))
123  strong_alias (__ieee754_logf, FN_PROTOTYPE_FAST(logf))