X-Git-Url: http://nsz.repo.hu/git/?p=libm;a=blobdiff_plain;f=src%2Fmath%2F__exp.c;h=ef14e5f57b7c59dd4b191b446efbed2bb9144d67;hp=83f8ac3ae68d3bb2e19d8beed32ce031342e6c10;hb=25215b63b9aa93089a9a05d1cffc3784109228c6;hpb=1eb8d023d8b5c286908af676cb405a2ba598d286 diff --git a/src/math/__exp.c b/src/math/__exp.c index 83f8ac3..ef14e5f 100644 --- a/src/math/__exp.c +++ b/src/math/__exp.c @@ -27,72 +27,25 @@ #include "libm.h" -static const uint32_t k = 1799; /* constant for reduction */ -static const double kln2 = 1246.97177782734161156; /* k * ln2 */ - -/* - * Compute exp(x), scaled to avoid spurious overflow. An exponent is - * returned separately in 'expt'. - * - * Input: ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91 - * Output: 2**1023 <= y < 2**1024 - */ -static double __frexp_exp(double x, int *expt) -{ - double exp_x; - uint32_t hx; - - /* - * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to - * minimize |exp(kln2) - 2**k|. We also scale the exponent of - * exp_x to MAX_EXP so that the result can be multiplied by - * a tiny number without losing accuracy due to denormalization. - */ - exp_x = exp(x - kln2); - GET_HIGH_WORD(hx, exp_x); - *expt = (hx >> 20) - (0x3ff + 1023) + k; - SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20)); - return exp_x; -} - /* - * __ldexp_exp(x, expt) and __ldexp_cexp(x, expt) compute exp(x) * 2**expt. - * They are intended for large arguments (real part >= ln(DBL_MAX)) - * where care is needed to avoid overflow. - * - * The present implementation is narrowly tailored for our hyperbolic and - * exponential functions. We assume expt is small (0 or -1), and the caller - * has filtered out very large x, for which overflow would be inevitable. + * We use exp(x) = exp(x - kln2) * 2**k, + * k is carefully chosen to minimize |exp(kln2) - 2**k| */ -double __ldexp_exp(double x, int expt) -{ - double exp_x, scale; - int ex_expt; +static const uint32_t k = 1799; +static const double kln2 = 1246.97177782734161156; - exp_x = __frexp_exp(x, &ex_expt); - expt += ex_expt; - INSERT_WORDS(scale, (0x3ff + expt) << 20, 0); - return exp_x * scale; -} - -double complex __ldexp_cexp(double complex z, int expt) +/* exp(x)/2 when x is huge */ +double __expo2(double x) { - double x, y, exp_x, scale1, scale2; - int ex_expt, half_expt; - - x = creal(z); - y = cimag(z); - exp_x = __frexp_exp(x, &ex_expt); - expt += ex_expt; + double scale; + int n; /* - * Arrange so that scale1 * scale2 == 2**expt. We use this to - * compensate for scalbn being horrendously slow. + * efficient scalbn(y, k-1): + * 2**(k-1) cannot be represented + * so we use that k-1 is even and scale in two steps */ - half_expt = expt / 2; - INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0); - half_expt = expt - half_expt; - INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0); - - return cpack(cos(y) * exp_x * scale1 * scale2, sin(y) * exp_x * scale1 * scale2); + n = (k - 1)/2; + INSERT_WORDS(scale, (0x3ff + n) << 20, 0); + return exp(x - kln2) * scale * scale; }