elf.h: add ELFCOMPRESS_ZSTD
[musl] / src / math / expf.c
index 3c3e2ab..f9fbf8e 100644 (file)
@@ -1,94 +1,80 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */
 /*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Single-precision e^x function.
  *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
+ * Copyright (c) 2017-2018, Arm Limited.
+ * SPDX-License-Identifier: MIT
  */
 
+#include <math.h>
+#include <stdint.h>
 #include "libm.h"
+#include "exp2f_data.h"
 
-static const float
-halF[2] = {0.5,-0.5,},
-huge    = 1.0e+30,
-o_threshold =  8.8721679688e+01,  /* 0x42b17180 */
-u_threshold = -1.0397208405e+02,  /* 0xc2cff1b5 */
-ln2HI[2]   = { 6.9314575195e-01,  /* 0x3f317200 */
-              -6.9314575195e-01,},/* 0xbf317200 */
-ln2LO[2]   = { 1.4286067653e-06,  /* 0x35bfbe8e */
-              -1.4286067653e-06,},/* 0xb5bfbe8e */
-invln2 = 1.4426950216e+00,        /* 0x3fb8aa3b */
 /*
- * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
- * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
- */
-P1 =  1.6666625440e-1, /*  0xaaaa8f.0p-26 */
-P2 = -2.7667332906e-3; /* -0xb55215.0p-32 */
+EXP2F_TABLE_BITS = 5
+EXP2F_POLY_ORDER = 3
 
-static const volatile float twom100 = 7.8886090522e-31; /* 2**-100=0x0d800000 */
+ULP error: 0.502 (nearest rounding.)
+Relative error: 1.69 * 2^-34 in [-ln2/64, ln2/64] (before rounding.)
+Wrong count: 170635 (all nearest rounding wrong results with fma.)
+Non-nearest ULP error: 1 (rounded ULP error)
+*/
 
-float expf(float x)
+#define N (1 << EXP2F_TABLE_BITS)
+#define InvLn2N __exp2f_data.invln2_scaled
+#define T __exp2f_data.tab
+#define C __exp2f_data.poly_scaled
+
+static inline uint32_t top12(float x)
 {
-       float y,hi=0.0,lo=0.0,c,t,twopk;
-       int32_t k=0,xsb;
-       uint32_t hx;
+       return asuint(x) >> 20;
+}
 
-       GET_FLOAT_WORD(hx, x);
-       xsb = (hx>>31)&1;  /* sign bit of x */
-       hx &= 0x7fffffff;  /* high word of |x| */
+float expf(float x)
+{
+       uint32_t abstop;
+       uint64_t ki, t;
+       double_t kd, xd, z, r, r2, y, s;
 
-       /* filter out non-finite argument */
-       if (hx >= 0x42b17218) {  /* if |x|>=88.721... */
-               if (hx > 0x7f800000)  /* NaN */
-                       return x+x;
-               if (hx == 0x7f800000)  /* exp(+-inf)={inf,0} */
-                       return xsb==0 ? x : 0.0;
-               if (x > o_threshold)
-                       return huge*huge; /* overflow */
-               if (x < u_threshold)
-                       return twom100*twom100; /* underflow */
+       xd = (double_t)x;
+       abstop = top12(x) & 0x7ff;
+       if (predict_false(abstop >= top12(88.0f))) {
+               /* |x| >= 88 or x is nan.  */
+               if (asuint(x) == asuint(-INFINITY))
+                       return 0.0f;
+               if (abstop >= top12(INFINITY))
+                       return x + x;
+               if (x > 0x1.62e42ep6f) /* x > log(0x1p128) ~= 88.72 */
+                       return __math_oflowf(0);
+               if (x < -0x1.9fe368p6f) /* x < log(0x1p-150) ~= -103.97 */
+                       return __math_uflowf(0);
        }
 
-       /* argument reduction */
-       if (hx > 0x3eb17218) {  /* if  |x| > 0.5 ln2 */
-               if (hx < 0x3F851592) {  /* and |x| < 1.5 ln2 */
-                       hi = x-ln2HI[xsb];
-                       lo = ln2LO[xsb];
-                       k = 1 - xsb - xsb;
-               } else {
-                       k  = invln2*x + halF[xsb];
-                       t  = k;
-                       hi = x - t*ln2HI[0];  /* t*ln2HI is exact here */
-                       lo = t*ln2LO[0];
-               }
-               STRICT_ASSIGN(float, x, hi - lo);
-       } else if(hx < 0x39000000)  {  /* |x|<2**-14 */
-               /* raise inexact */
-               if (huge+x > 1.0f)
-                       return 1.0f + x;
-       } else
-               k = 0;
+       /* x*N/Ln2 = k + r with r in [-1/2, 1/2] and int k.  */
+       z = InvLn2N * xd;
+
+       /* Round and convert z to int, the result is in [-150*N, 128*N] and
+          ideally ties-to-even rule is used, otherwise the magnitude of r
+          can be bigger which gives larger approximation error.  */
+#if TOINT_INTRINSICS
+       kd = roundtoint(z);
+       ki = converttoint(z);
+#else
+# define SHIFT __exp2f_data.shift
+       kd = eval_as_double(z + SHIFT);
+       ki = asuint64(kd);
+       kd -= SHIFT;
+#endif
+       r = z - kd;
 
-       /* x is now in primary range */
-       t = x*x;
-       if (k >= -125)
-               SET_FLOAT_WORD(twopk, 0x3f800000+(k<<23));
-       else
-               SET_FLOAT_WORD(twopk, 0x3f800000+((k+100)<<23));
-       c  = x - t*(P1+t*P2);
-       if (k == 0)
-               return 1.0f - ((x*c)/(c - 2.0f) - x);
-       y = 1.0f - ((lo - (x*c)/(2.0f - c)) - hi);
-       if (k < -125)
-               return y*twopk*twom100;
-       if (k == 128)
-               return y*2.0f*0x1p127f;
-       return y*twopk;
+       /* exp(x) = 2^(k/N) * 2^(r/N) ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */
+       t = T[ki % N];
+       t += ki << (52 - EXP2F_TABLE_BITS);
+       s = asdouble(t);
+       z = C[0] * r + C[1];
+       r2 = r * r;
+       y = C[2] * r + 1;
+       y = z * r2 + y;
+       y = y * s;
+       return eval_as_float(y);
 }