about summary refs log tree commit diff
path: root/sysdeps/ieee754/dbl-64/e_exp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/ieee754/dbl-64/e_exp.c')
-rw-r--r--sysdeps/ieee754/dbl-64/e_exp.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/sysdeps/ieee754/dbl-64/e_exp.c b/sysdeps/ieee754/dbl-64/e_exp.c
new file mode 100644
index 0000000000..ee0b22f6ae
--- /dev/null
+++ b/sysdeps/ieee754/dbl-64/e_exp.c
@@ -0,0 +1,162 @@
+/* Double-precision floating point e^x.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Geoffrey Keating <geoffk@ozemail.com.au>
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* How this works:
+   The basic design here is from
+   Shmuel Gal and Boris Bachelis, "An Accurate Elementary Mathematical
+   Library for the IEEE Floating Point Standard", ACM Trans. Math. Soft.,
+   17 (1), March 1991, pp. 26-45.
+
+   The input value, x, is written as
+
+   x = n * ln(2)_0 + t/512 + delta[t] + x + n * ln(2)_1
+
+   where:
+   - n is an integer, 1024 >= n >= -1075;
+   - ln(2)_0 is the first 43 bits of ln(2), and ln(2)_1 is the remainder, so
+     that |ln(2)_1| < 2^-32;
+   - t is an integer, 177 >= t >= -177
+   - delta is based on a table entry, delta[t] < 2^-28
+   - x is whatever is left, |x| < 2^-10
+
+   Then e^x is approximated as
+
+   e^x = 2^n_1 ( 2^n_0 e^(t/512 + delta[t])
+               + ( 2^n_0 e^(t/512 + delta[t])
+                   * ( p(x + n * ln(2)_1)
+                       - n*ln(2)_1
+                       - n*ln(2)_1 * p(x + n * ln(2)_1) ) ) )
+
+   where
+   - p(x) is a polynomial approximating e(x)-1;
+   - e^(t/512 + delta[t]) is obtained from a table;
+   - n_1 + n_0 = n, so that |n_0| < DBL_MIN_EXP-1.
+
+   If it happens that n_1 == 0 (this is the usual case), that multiplication
+   is omitted.
+   */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <float.h>
+#include <ieee754.h>
+#include <math.h>
+#include <fenv.h>
+#include <inttypes.h>
+#include <math_private.h>
+
+extern const float __exp_deltatable[178];
+extern const double __exp_atable[355] /* __attribute__((mode(DF))) */;
+
+static const volatile double TWO1023 = 8.988465674311579539e+307;
+static const volatile double TWOM1000 = 9.3326361850321887899e-302;
+
+double
+__ieee754_exp (double x)
+{
+  static const double himark = 709.7827128933840868;
+  static const double lomark = -745.1332191019412221;
+  /* Check for usual case.  */
+  if (isless (x, himark) && isgreater (x, lomark))
+    {
+      static const double THREEp42 = 13194139533312.0;
+      static const double THREEp51 = 6755399441055744.0;
+      /* 1/ln(2).  */
+      static const double M_1_LN2 = 1.442695040888963387;
+      /* ln(2), part 1 */
+      static const double M_LN2_0 = .6931471805598903302;
+      /* ln(2), part 2 */
+      static const double M_LN2_1 = 5.497923018708371155e-14;
+
+      int tval, unsafe, n_i;
+      double x22, n, t, dely, result;
+      union ieee754_double ex2_u, scale_u;
+      fenv_t oldenv;
+
+      feholdexcept (&oldenv);
+#ifdef FE_TONEAREST
+      fesetround (FE_TONEAREST);
+#endif
+
+      /* Calculate n.  */
+      n = x * M_1_LN2 + THREEp51;
+      n -= THREEp51;
+      x = x - n*M_LN2_0;
+
+      /* Calculate t/512.  */
+      t = x + THREEp42;
+      t -= THREEp42;
+      x -= t;
+
+      /* Compute tval = t.  */
+      tval = (int) (t * 512.0);
+
+      if (t >= 0)
+	x -= __exp_deltatable[tval];
+      else
+	x += __exp_deltatable[-tval];
+
+      /* Now, the variable x contains x + n*ln(2)_1.  */
+      dely = n*M_LN2_1;
+
+      /* Compute ex2 = 2^n_0 e^(t/512+delta[t]).  */
+      ex2_u.d = __exp_atable[tval+177];
+      n_i = (int)n;
+      /* 'unsafe' is 1 iff n_1 != 0.  */
+      unsafe = abs(n_i) >= -DBL_MIN_EXP - 1;
+      ex2_u.ieee.exponent += n_i >> unsafe;
+
+      /* Compute scale = 2^n_1.  */
+      scale_u.d = 1.0;
+      scale_u.ieee.exponent += n_i - (n_i >> unsafe);
+
+      /* Approximate e^x2 - 1, using a fourth-degree polynomial,
+	 with maximum error in [-2^-10-2^-28,2^-10+2^-28]
+	 less than 4.9e-19.  */
+      x22 = (((0.04166666898464281565
+	       * x + 0.1666666766008501610)
+	      * x + 0.499999999999990008)
+	     * x + 0.9999999999999976685) * x;
+      /* Allow for impact of dely.  */
+      x22 -= dely + dely*x22;
+
+      /* Return result.  */
+      fesetenv (&oldenv);
+
+      result = x22 * ex2_u.d + ex2_u.d;
+      if (!unsafe)
+	return result;
+      else
+	return result * scale_u.d;
+    }
+  /* Exceptional cases:  */
+  else if (isless (x, himark))
+    {
+      if (__isinf (x))
+	/* e^-inf == 0, with no error.  */
+	return 0;
+      else
+	/* Underflow */
+	return TWOM1000 * TWOM1000;
+    }
+  else
+    /* Return x, if x is a NaN or Inf; or overflow, otherwise.  */
+    return TWO1023*x;
+}