Blame sysdeps/ieee754/ldbl-128/s_expm1l.c

Packit 6c4009
/*							expm1l.c
Packit 6c4009
 *
Packit 6c4009
 *	Exponential function, minus 1
Packit 6c4009
 *      128-bit long double precision
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 * SYNOPSIS:
Packit 6c4009
 *
Packit 6c4009
 * long double x, y, expm1l();
Packit 6c4009
 *
Packit 6c4009
 * y = expm1l( x );
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 * DESCRIPTION:
Packit 6c4009
 *
Packit 6c4009
 * Returns e (2.71828...) raised to the x power, minus one.
Packit 6c4009
 *
Packit 6c4009
 * Range reduction is accomplished by separating the argument
Packit 6c4009
 * into an integer k and fraction f such that
Packit 6c4009
 *
Packit 6c4009
 *     x    k  f
Packit 6c4009
 *    e  = 2  e.
Packit 6c4009
 *
Packit 6c4009
 * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1
Packit 6c4009
 * in the basic range [-0.5 ln 2, 0.5 ln 2].
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 * ACCURACY:
Packit 6c4009
 *
Packit 6c4009
 *                      Relative error:
Packit 6c4009
 * arithmetic   domain     # trials      peak         rms
Packit 6c4009
 *    IEEE    -79,+MAXLOG    100,000     1.7e-34     4.5e-35
Packit 6c4009
 *
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/* Copyright 2001 by Stephen L. Moshier
Packit 6c4009
Packit 6c4009
    This library is free software; you can redistribute it and/or
Packit 6c4009
    modify it under the terms of the GNU Lesser General Public
Packit 6c4009
    License as published by the Free Software Foundation; either
Packit 6c4009
    version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
    This library is distributed in the hope that it will be useful,
Packit 6c4009
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
    Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
    You should have received a copy of the GNU Lesser General Public
Packit 6c4009
    License along with this library; if not, see
Packit 6c4009
    <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <float.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <math-underflow.h>
Packit 6c4009
#include <libm-alias-ldouble.h>
Packit 6c4009
Packit 6c4009
/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x)
Packit 6c4009
   -.5 ln 2  <  x  <  .5 ln 2
Packit 6c4009
   Theoretical peak relative error = 8.1e-36  */
Packit 6c4009
Packit 6c4009
static const _Float128
Packit 6c4009
  P0 = L(2.943520915569954073888921213330863757240E8),
Packit 6c4009
  P1 = L(-5.722847283900608941516165725053359168840E7),
Packit 6c4009
  P2 = L(8.944630806357575461578107295909719817253E6),
Packit 6c4009
  P3 = L(-7.212432713558031519943281748462837065308E5),
Packit 6c4009
  P4 = L(4.578962475841642634225390068461943438441E4),
Packit 6c4009
  P5 = L(-1.716772506388927649032068540558788106762E3),
Packit 6c4009
  P6 = L(4.401308817383362136048032038528753151144E1),
Packit 6c4009
  P7 = L(-4.888737542888633647784737721812546636240E-1),
Packit 6c4009
  Q0 = L(1.766112549341972444333352727998584753865E9),
Packit 6c4009
  Q1 = L(-7.848989743695296475743081255027098295771E8),
Packit 6c4009
  Q2 = L(1.615869009634292424463780387327037251069E8),
Packit 6c4009
  Q3 = L(-2.019684072836541751428967854947019415698E7),
Packit 6c4009
  Q4 = L(1.682912729190313538934190635536631941751E6),
Packit 6c4009
  Q5 = L(-9.615511549171441430850103489315371768998E4),
Packit 6c4009
  Q6 = L(3.697714952261803935521187272204485251835E3),
Packit 6c4009
  Q7 = L(-8.802340681794263968892934703309274564037E1),
Packit 6c4009
  /* Q8 = 1.000000000000000000000000000000000000000E0 */
Packit 6c4009
/* C1 + C2 = ln 2 */
Packit 6c4009
Packit 6c4009
  C1 = L(6.93145751953125E-1),
Packit 6c4009
  C2 = L(1.428606820309417232121458176568075500134E-6),
Packit 6c4009
/* ln 2^-114 */
Packit 6c4009
  minarg = L(-7.9018778583833765273564461846232128760607E1), big = L(1e4932);
Packit 6c4009
Packit 6c4009
Packit 6c4009
_Float128
Packit 6c4009
__expm1l (_Float128 x)
Packit 6c4009
{
Packit 6c4009
  _Float128 px, qx, xx;
Packit 6c4009
  int32_t ix, sign;
Packit 6c4009
  ieee854_long_double_shape_type u;
Packit 6c4009
  int k;
Packit 6c4009
Packit 6c4009
  /* Detect infinity and NaN.  */
Packit 6c4009
  u.value = x;
Packit 6c4009
  ix = u.parts32.w0;
Packit 6c4009
  sign = ix & 0x80000000;
Packit 6c4009
  ix &= 0x7fffffff;
Packit 6c4009
  if (!sign && ix >= 0x40060000)
Packit 6c4009
    {
Packit 6c4009
      /* If num is positive and exp >= 6 use plain exp.  */
Packit 6c4009
      return __expl (x);
Packit 6c4009
    }
Packit 6c4009
  if (ix >= 0x7fff0000)
Packit 6c4009
    {
Packit 6c4009
      /* Infinity (which must be negative infinity). */
Packit 6c4009
      if (((ix & 0xffff) | u.parts32.w1 | u.parts32.w2 | u.parts32.w3) == 0)
Packit 6c4009
	return -1;
Packit 6c4009
      /* NaN.  Invalid exception if signaling.  */
Packit 6c4009
      return x + x;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* expm1(+- 0) = +- 0.  */
Packit 6c4009
  if ((ix == 0) && (u.parts32.w1 | u.parts32.w2 | u.parts32.w3) == 0)
Packit 6c4009
    return x;
Packit 6c4009
Packit 6c4009
  /* Minimum value.  */
Packit 6c4009
  if (x < minarg)
Packit 6c4009
    return (4.0/big - 1);
Packit 6c4009
Packit 6c4009
  /* Avoid internal underflow when result does not underflow, while
Packit 6c4009
     ensuring underflow (without returning a zero of the wrong sign)
Packit 6c4009
     when the result does underflow.  */
Packit 6c4009
  if (fabsl (x) < L(0x1p-113))
Packit 6c4009
    {
Packit 6c4009
      math_check_force_underflow (x);
Packit 6c4009
      return x;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */
Packit 6c4009
  xx = C1 + C2;			/* ln 2. */
Packit 6c4009
  px = __floorl (0.5 + x / xx);
Packit 6c4009
  k = px;
Packit 6c4009
  /* remainder times ln 2 */
Packit 6c4009
  x -= px * C1;
Packit 6c4009
  x -= px * C2;
Packit 6c4009
Packit 6c4009
  /* Approximate exp(remainder ln 2).  */
Packit 6c4009
  px = (((((((P7 * x
Packit 6c4009
	      + P6) * x
Packit 6c4009
	     + P5) * x + P4) * x + P3) * x + P2) * x + P1) * x + P0) * x;
Packit 6c4009
Packit 6c4009
  qx = (((((((x
Packit 6c4009
	      + Q7) * x
Packit 6c4009
	     + Q6) * x + Q5) * x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0;
Packit 6c4009
Packit 6c4009
  xx = x * x;
Packit 6c4009
  qx = x + (0.5 * xx + xx * px / qx);
Packit 6c4009
Packit 6c4009
  /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2).
Packit 6c4009
Packit 6c4009
  We have qx = exp(remainder ln 2) - 1, so
Packit 6c4009
  exp(x) - 1 = 2^k (qx + 1) - 1
Packit 6c4009
             = 2^k qx + 2^k - 1.  */
Packit 6c4009
Packit 6c4009
  px = __ldexpl (1, k);
Packit 6c4009
  x = px * qx + (px - 1.0);
Packit 6c4009
  return x;
Packit 6c4009
}
Packit 6c4009
libm_hidden_def (__expm1l)
Packit 6c4009
libm_alias_ldouble (__expm1, expm1)