aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/ieee754/dbl-64/e_exp.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2017-12-19 18:11:37 +0000
committerJoseph Myers <joseph@codesourcery.com>2017-12-19 18:11:37 +0000
commitf1e005022ebd246e1541386cd2f3286f008d2d98 (patch)
treedc80cd25916cd4cb63da26f9a6e32036157977af /sysdeps/ieee754/dbl-64/e_exp.c
parente184ac3a105a4a45b920bf2cdaa701a683c781a2 (diff)
downloadglibc-f1e005022ebd246e1541386cd2f3286f008d2d98.tar
glibc-f1e005022ebd246e1541386cd2f3286f008d2d98.tar.gz
glibc-f1e005022ebd246e1541386cd2f3286f008d2d98.tar.bz2
glibc-f1e005022ebd246e1541386cd2f3286f008d2d98.zip
Revert exp reimplementation (causes test failures).
Revert: 2017-12-19 Joseph Myers <joseph@codesourcery.com> * sysdeps/x86_64/fpu/libm-test-ulps: Update. 2017-12-19 Patrick McGehearty <patrick.mcgehearty@oracle.com> * sysdeps/ieee754/dbl-64/e_exp.c: Include <math-svid-compat.h> and <errno.h>. Include "eexp.tbl". (half): New constant. (one): Likewise. (__ieee754_exp): Rewrite. (__slowexp): Remove prototype. * sysdeps/ieee754/dbl-64/eexp.tbl: New file. * sysdeps/ieee754/dbl-64/slowexp.c: Remove file. * sysdeps/i386/fpu/slowexp.c: Likewise. * sysdeps/ia64/fpu/slowexp.c: Likewise. * sysdeps/m68k/m680x0/fpu/slowexp.c: Likewise. * sysdeps/x86_64/fpu/multiarch/slowexp-avx.c: Likewise. * sysdeps/x86_64/fpu/multiarch/slowexp-fma.c: Likewise. * sysdeps/x86_64/fpu/multiarch/slowexp-fma4.c: Likewise. * sysdeps/generic/math_private.h (__slowexp): Remove prototype. * sysdeps/ieee754/dbl-64/e_pow.c: Remove mention of slowexp.c in comment. * sysdeps/powerpc/power4/fpu/Makefile [$(subdir) = math] (CPPFLAGS-slowexp.c): Remove variable. * sysdeps/x86_64/fpu/multiarch/Makefile (libm-sysdep_routines): Remove slowexp-fma, slowexp-fma4 and slowexp-avx. (CFLAGS-slowexp-fma.c): Remove variable. (CFLAGS-slowexp-fma4.c): Likewise. (CFLAGS-slowexp-avx.c): Likewise. * sysdeps/x86_64/fpu/multiarch/e_exp-avx.c (__slowexp): Do not define as macro. * sysdeps/x86_64/fpu/multiarch/e_exp-fma.c (__slowexp): Likewise. * sysdeps/x86_64/fpu/multiarch/e_exp-fma4.c (__slowexp): Likewise. * math/Makefile (type-double-routines): Remove slowexp. * manual/probes.texi (slowexp_p6): Remove. (slowexp_p32): Likewise.
Diffstat (limited to 'sysdeps/ieee754/dbl-64/e_exp.c')
-rw-r--r--sysdeps/ieee754/dbl-64/e_exp.c398
1 files changed, 183 insertions, 215 deletions
diff --git a/sysdeps/ieee754/dbl-64/e_exp.c b/sysdeps/ieee754/dbl-64/e_exp.c
index 6a7122f585..6757a14ce1 100644
--- a/sysdeps/ieee754/dbl-64/e_exp.c
+++ b/sysdeps/ieee754/dbl-64/e_exp.c
@@ -1,4 +1,3 @@
-/* EXP function - Compute double precision exponential */
/*
* IBM Accurate Mathematical Library
* written by International Business Machines Corp.
@@ -24,7 +23,7 @@
/* exp1 */
/* */
/* FILES NEEDED:dla.h endian.h mpa.h mydefs.h uexp.h */
-/* mpa.c mpexp.x */
+/* mpa.c mpexp.x slowexp.c */
/* */
/* An ultimate exp routine. Given an IEEE double machine number x */
/* it computes the correctly rounded (to nearest) value of e^x */
@@ -33,238 +32,207 @@
/* */
/***************************************************************************/
-/* IBM exp(x) replaced by following exp(x) in 2017. IBM exp1(x,xx) remains. */
-/* exp(x)
- Hybrid algorithm of Peter Tang's Table driven method (for large
- arguments) and an accurate table (for small arguments).
- Written by K.C. Ng, November 1988.
- Revised by Patrick McGehearty, Nov 2017 to use j/64 instead of j/32
- Method (large arguments):
- 1. Argument Reduction: given the input x, find r and integer k
- and j such that
- x = (k+j/64)*(ln2) + r, |r| <= (1/128)*ln2
-
- 2. exp(x) = 2^k * (2^(j/64) + 2^(j/64)*expm1(r))
- a. expm1(r) is approximated by a polynomial:
- expm1(r) ~ r + t1*r^2 + t2*r^3 + ... + t5*r^6
- Here t1 = 1/2 exactly.
- b. 2^(j/64) is represented to twice double precision
- as TBL[2j]+TBL[2j+1].
-
- Note: If divide were fast enough, we could use another approximation
- in 2.a:
- expm1(r) ~ (2r)/(2-R), R = r - r^2*(t1 + t2*r^2)
- (for the same t1 and t2 as above)
-
- Special cases:
- exp(INF) is INF, exp(NaN) is NaN;
- exp(-INF)= 0;
- for finite argument, only exp(0)=1 is exact.
-
- Accuracy:
- According to an error analysis, the error is always less than
- an ulp (unit in the last place). The largest errors observed
- are less than 0.55 ulp for normal results and less than 0.75 ulp
- for subnormal results.
-
- Misc. info.
- For IEEE double
- if x > 7.09782712893383973096e+02 then exp(x) overflow
- if x < -7.45133219101941108420e+02 then exp(x) underflow. */
-
#include <math.h>
-#include <math-svid-compat.h>
-#include <math_private.h>
-#include <errno.h>
#include "endian.h"
#include "uexp.h"
-#include "uexp.tbl"
#include "mydefs.h"
#include "MathLib.h"
+#include "uexp.tbl"
+#include <math_private.h>
#include <fenv.h>
#include <float.h>
-extern double __ieee754_exp (double);
-
-#include "eexp.tbl"
-
-static const double
- half = 0.5,
- one = 1.0;
+#ifndef SECTION
+# define SECTION
+#endif
+double __slowexp (double);
+/* An ultimate exp routine. Given an IEEE double machine number x it computes
+ the correctly rounded (to nearest) value of e^x. */
double
-__ieee754_exp (double x_arg)
+SECTION
+__ieee754_exp (double x)
{
- double z, t;
+ double bexp, t, eps, del, base, y, al, bet, res, rem, cor;
+ mynumber junk1, junk2, binexp = {{0, 0}};
+ int4 i, j, m, n, ex;
double retval;
- int hx, ix, k, j, m;
- int fe_val;
- union
- {
- int i_part[2];
- double x;
- } xx;
- union
- {
- int y_part[2];
- double y;
- } yy;
- xx.x = x_arg;
-
- ix = xx.i_part[HIGH_HALF];
- hx = ix & ~0x80000000;
-
- if (hx < 0x3ff0a2b2)
- { /* |x| < 3/2 ln 2 */
- if (hx < 0x3f862e42)
- { /* |x| < 1/64 ln 2 */
- if (hx < 0x3ed00000)
- { /* |x| < 2^-18 */
- if (hx < 0x3e300000)
- {
- retval = one + xx.x;
- return retval;
- }
- retval = one + xx.x * (one + half * xx.x);
- return retval;
- }
- /* Use FE_TONEAREST rounding mode for computing yy.y.
- Avoid set/reset of rounding mode if in FE_TONEAREST mode. */
- fe_val = get_rounding_mode ();
- if (fe_val == FE_TONEAREST)
- {
- t = xx.x * xx.x;
- yy.y = xx.x + (t * (half + xx.x * t2)
- + (t * t) * (t3 + xx.x * t4 + t * t5));
- retval = one + yy.y;
- }
- else
- {
- libc_fesetround (FE_TONEAREST);
- t = xx.x * xx.x;
- yy.y = xx.x + (t * (half + xx.x * t2)
- + (t * t) * (t3 + xx.x * t4 + t * t5));
- retval = one + yy.y;
- libc_fesetround (fe_val);
- }
- return retval;
- }
-
- /* Find the multiple of 2^-6 nearest x. */
- k = hx >> 20;
- j = (0x00100000 | (hx & 0x000fffff)) >> (0x40c - k);
- j = (j - 1) & ~1;
- if (ix < 0)
- j += 134;
- /* Use FE_TONEAREST rounding mode for computing yy.y.
- Avoid set/reset of rounding mode if in FE_TONEAREST mode. */
- fe_val = get_rounding_mode ();
- if (fe_val == FE_TONEAREST)
- {
- z = xx.x - TBL2[j];
- t = z * z;
- yy.y = z + (t * (half + (z * t2))
- + (t * t) * (t3 + z * t4 + t * t5));
- retval = TBL2[j + 1] + TBL2[j + 1] * yy.y;
- }
- else
- {
- libc_fesetround (FE_TONEAREST);
- z = xx.x - TBL2[j];
- t = z * z;
- yy.y = z + (t * (half + (z * t2))
- + (t * t) * (t3 + z * t4 + t * t5));
- retval = TBL2[j + 1] + TBL2[j + 1] * yy.y;
- libc_fesetround (fe_val);
- }
- return retval;
- }
-
- if (hx >= 0x40862e42)
- { /* x is large, infinite, or nan. */
- if (hx >= 0x7ff00000)
- {
- if (ix == 0xfff00000 && xx.i_part[LOW_HALF] == 0)
- return zero; /* exp(-inf) = 0. */
- return (xx.x * xx.x); /* exp(nan/inf) is nan or inf. */
- }
- if (xx.x > threshold1)
- { /* Set overflow error condition. */
- retval = hhuge * hhuge;
- return retval;
- }
- if (-xx.x > threshold2)
- { /* Set underflow error condition. */
- double force_underflow = tiny * tiny;
- math_force_eval (force_underflow);
- retval = force_underflow;
- return retval;
- }
- }
-
- /* Use FE_TONEAREST rounding mode for computing yy.y.
- Avoid set/reset of rounding mode if already in FE_TONEAREST mode. */
- fe_val = get_rounding_mode ();
- if (fe_val == FE_TONEAREST)
- {
- t = invln2_64 * xx.x;
- if (ix < 0)
- t -= half;
- else
- t += half;
- k = (int) t;
- j = (k & 0x3f) << 1;
- m = k >> 6;
- z = (xx.x - k * ln2_64hi) - k * ln2_64lo;
-
- /* z is now in primary range. */
- t = z * z;
- yy.y = z + (t * (half + z * t2) + (t * t) * (t3 + z * t4 + t * t5));
- yy.y = TBL[j] + (TBL[j + 1] + TBL[j] * yy.y);
- }
- else
- {
- libc_fesetround (FE_TONEAREST);
- t = invln2_64 * xx.x;
- if (ix < 0)
- t -= half;
- else
- t += half;
- k = (int) t;
- j = (k & 0x3f) << 1;
- m = k >> 6;
- z = (xx.x - k * ln2_64hi) - k * ln2_64lo;
-
- /* z is now in primary range. */
- t = z * z;
- yy.y = z + (t * (half + z * t2) + (t * t) * (t3 + z * t4 + t * t5));
- yy.y = TBL[j] + (TBL[j + 1] + TBL[j] * yy.y);
- libc_fesetround (fe_val);
- }
- if (m < -1021)
- {
- yy.y_part[HIGH_HALF] += (m + 54) << 20;
- retval = twom54 * yy.y;
- if (retval < DBL_MIN)
- {
- double force_underflow = tiny * tiny;
- math_force_eval (force_underflow);
- }
- return retval;
- }
- yy.y_part[HIGH_HALF] += m << 20;
- return yy.y;
+ {
+ SET_RESTORE_ROUND (FE_TONEAREST);
+
+ junk1.x = x;
+ m = junk1.i[HIGH_HALF];
+ n = m & hugeint;
+
+ if (n > smallint && n < bigint)
+ {
+ y = x * log2e.x + three51.x;
+ bexp = y - three51.x; /* multiply the result by 2**bexp */
+
+ junk1.x = y;
+
+ eps = bexp * ln_two2.x; /* x = bexp*ln(2) + t - eps */
+ t = x - bexp * ln_two1.x;
+
+ y = t + three33.x;
+ base = y - three33.x; /* t rounded to a multiple of 2**-18 */
+ junk2.x = y;
+ del = (t - base) - eps; /* x = bexp*ln(2) + base + del */
+ eps = del + del * del * (p3.x * del + p2.x);
+
+ binexp.i[HIGH_HALF] = (junk1.i[LOW_HALF] + 1023) << 20;
+
+ i = ((junk2.i[LOW_HALF] >> 8) & 0xfffffffe) + 356;
+ j = (junk2.i[LOW_HALF] & 511) << 1;
+
+ al = coar.x[i] * fine.x[j];
+ bet = ((coar.x[i] * fine.x[j + 1] + coar.x[i + 1] * fine.x[j])
+ + coar.x[i + 1] * fine.x[j + 1]);
+
+ rem = (bet + bet * eps) + al * eps;
+ res = al + rem;
+ cor = (al - res) + rem;
+ if (res == (res + cor * err_0))
+ {
+ retval = res * binexp.x;
+ goto ret;
+ }
+ else
+ {
+ retval = __slowexp (x);
+ goto ret;
+ } /*if error is over bound */
+ }
+
+ if (n <= smallint)
+ {
+ retval = 1.0;
+ goto ret;
+ }
+
+ if (n >= badint)
+ {
+ if (n > infint)
+ {
+ retval = x + x;
+ goto ret;
+ } /* x is NaN */
+ if (n < infint)
+ {
+ if (x > 0)
+ goto ret_huge;
+ else
+ goto ret_tiny;
+ }
+ /* x is finite, cause either overflow or underflow */
+ if (junk1.i[LOW_HALF] != 0)
+ {
+ retval = x + x;
+ goto ret;
+ } /* x is NaN */
+ retval = (x > 0) ? inf.x : zero; /* |x| = inf; return either inf or 0 */
+ goto ret;
+ }
+
+ y = x * log2e.x + three51.x;
+ bexp = y - three51.x;
+ junk1.x = y;
+ eps = bexp * ln_two2.x;
+ t = x - bexp * ln_two1.x;
+ y = t + three33.x;
+ base = y - three33.x;
+ junk2.x = y;
+ del = (t - base) - eps;
+ eps = del + del * del * (p3.x * del + p2.x);
+ i = ((junk2.i[LOW_HALF] >> 8) & 0xfffffffe) + 356;
+ j = (junk2.i[LOW_HALF] & 511) << 1;
+ al = coar.x[i] * fine.x[j];
+ bet = ((coar.x[i] * fine.x[j + 1] + coar.x[i + 1] * fine.x[j])
+ + coar.x[i + 1] * fine.x[j + 1]);
+ rem = (bet + bet * eps) + al * eps;
+ res = al + rem;
+ cor = (al - res) + rem;
+ if (m >> 31)
+ {
+ ex = junk1.i[LOW_HALF];
+ if (res < 1.0)
+ {
+ res += res;
+ cor += cor;
+ ex -= 1;
+ }
+ if (ex >= -1022)
+ {
+ binexp.i[HIGH_HALF] = (1023 + ex) << 20;
+ if (res == (res + cor * err_0))
+ {
+ retval = res * binexp.x;
+ goto ret;
+ }
+ else
+ {
+ retval = __slowexp (x);
+ goto check_uflow_ret;
+ } /*if error is over bound */
+ }
+ ex = -(1022 + ex);
+ binexp.i[HIGH_HALF] = (1023 - ex) << 20;
+ res *= binexp.x;
+ cor *= binexp.x;
+ eps = 1.0000000001 + err_0 * binexp.x;
+ t = 1.0 + res;
+ y = ((1.0 - t) + res) + cor;
+ res = t + y;
+ cor = (t - res) + y;
+ if (res == (res + eps * cor))
+ {
+ binexp.i[HIGH_HALF] = 0x00100000;
+ retval = (res - 1.0) * binexp.x;
+ goto check_uflow_ret;
+ }
+ else
+ {
+ retval = __slowexp (x);
+ goto check_uflow_ret;
+ } /* if error is over bound */
+ check_uflow_ret:
+ if (retval < DBL_MIN)
+ {
+ double force_underflow = tiny * tiny;
+ math_force_eval (force_underflow);
+ }
+ if (retval == 0)
+ goto ret_tiny;
+ goto ret;
+ }
+ else
+ {
+ binexp.i[HIGH_HALF] = (junk1.i[LOW_HALF] + 767) << 20;
+ if (res == (res + cor * err_0))
+ retval = res * binexp.x * t256.x;
+ else
+ retval = __slowexp (x);
+ if (isinf (retval))
+ goto ret_huge;
+ else
+ goto ret;
+ }
+ }
+ret:
+ return retval;
+
+ ret_huge:
+ return hhuge * hhuge;
+
+ ret_tiny:
+ return tiny * tiny;
}
#ifndef __ieee754_exp
strong_alias (__ieee754_exp, __exp_finite)
#endif
-#ifndef SECTION
-# define SECTION
-#endif
-
/* Compute e^(x+xx). The routine also receives bound of error of previous
calculation. If after computing exp the error exceeds the allowed bounds,
the routine returns a non-positive number. Otherwise it returns the