Blame sysdeps/ieee754/dbl-64/e_exp2.c

Packit 6c4009
/* Double-precision floating point 2^x.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Geoffrey Keating <geoffk@ozemail.com.au>
Packit 6c4009
Packit 6c4009
   The GNU C 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
   The GNU C 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 the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* The basic design here is from
Packit 6c4009
   Shmuel Gal and Boris Bachelis, "An Accurate Elementary Mathematical
Packit 6c4009
   Library for the IEEE Floating Point Standard", ACM Trans. Math. Soft.,
Packit 6c4009
   17 (1), March 1991, pp. 26-45.
Packit 6c4009
   It has been slightly modified to compute 2^x instead of e^x.
Packit 6c4009
   */
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <float.h>
Packit 6c4009
#include <ieee754.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <fenv.h>
Packit 6c4009
#include <inttypes.h>
Packit 6c4009
#include <math-barriers.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <math-underflow.h>
Packit 6c4009
Packit 6c4009
#include "t_exp2.h"
Packit 6c4009
Packit 6c4009
static const double TWO1023 = 8.988465674311579539e+307;
Packit 6c4009
static const double TWOM1000 = 9.3326361850321887899e-302;
Packit 6c4009
Packit 6c4009
double
Packit 6c4009
__ieee754_exp2 (double x)
Packit 6c4009
{
Packit 6c4009
  static const double himark = (double) DBL_MAX_EXP;
Packit 6c4009
  static const double lomark = (double) (DBL_MIN_EXP - DBL_MANT_DIG - 1);
Packit 6c4009
Packit 6c4009
  /* Check for usual case.  */
Packit 6c4009
  if (__glibc_likely (isless (x, himark)))
Packit 6c4009
    {
Packit 6c4009
      /* Exceptional cases:  */
Packit 6c4009
      if (__glibc_unlikely (!isgreaterequal (x, lomark)))
Packit 6c4009
	{
Packit 6c4009
	  if (isinf (x))
Packit 6c4009
	    /* e^-inf == 0, with no error.  */
Packit 6c4009
	    return 0;
Packit 6c4009
	  else
Packit 6c4009
	    /* Underflow */
Packit 6c4009
	    return TWOM1000 * TWOM1000;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      static const double THREEp42 = 13194139533312.0;
Packit 6c4009
      int tval, unsafe;
Packit 6c4009
      double rx, x22, result;
Packit 6c4009
      union ieee754_double ex2_u, scale_u;
Packit 6c4009
Packit 6c4009
      if (fabs (x) < DBL_EPSILON / 4.0)
Packit 6c4009
	return 1.0 + x;
Packit 6c4009
Packit 6c4009
      {
Packit 6c4009
	SET_RESTORE_ROUND_NOEX (FE_TONEAREST);
Packit 6c4009
Packit 6c4009
	/* 1. Argument reduction.
Packit 6c4009
	   Choose integers ex, -256 <= t < 256, and some real
Packit 6c4009
	   -1/1024 <= x1 <= 1024 so that
Packit 6c4009
	   x = ex + t/512 + x1.
Packit 6c4009
Packit 6c4009
	   First, calculate rx = ex + t/512.  */
Packit 6c4009
	rx = x + THREEp42;
Packit 6c4009
	rx -= THREEp42;
Packit 6c4009
	x -= rx;  /* Compute x=x1. */
Packit 6c4009
	/* Compute tval = (ex*512 + t)+256.
Packit 6c4009
	   Now, t = (tval mod 512)-256 and ex=tval/512  [that's mod, NOT %;
Packit 6c4009
	   and /-round-to-nearest not the usual c integer /].  */
Packit 6c4009
	tval = (int) (rx * 512.0 + 256.0);
Packit 6c4009
Packit 6c4009
	/* 2. Adjust for accurate table entry.
Packit 6c4009
	   Find e so that
Packit 6c4009
	   x = ex + t/512 + e + x2
Packit 6c4009
	   where -1e6 < e < 1e6, and
Packit 6c4009
	   (double)(2^(t/512+e))
Packit 6c4009
	   is accurate to one part in 2^-64.  */
Packit 6c4009
Packit 6c4009
	/* 'tval & 511' is the same as 'tval%512' except that it's always
Packit 6c4009
	   positive.
Packit 6c4009
	   Compute x = x2.  */
Packit 6c4009
	x -= exp2_deltatable[tval & 511];
Packit 6c4009
Packit 6c4009
	/* 3. Compute ex2 = 2^(t/512+e+ex).  */
Packit 6c4009
	ex2_u.d = exp2_accuratetable[tval & 511];
Packit 6c4009
	tval >>= 9;
Packit 6c4009
	/* x2 is an integer multiple of 2^-54; avoid intermediate
Packit 6c4009
	   underflow from the calculation of x22 * x.  */
Packit 6c4009
	unsafe = abs (tval) >= -DBL_MIN_EXP - 56;
Packit 6c4009
	ex2_u.ieee.exponent += tval >> unsafe;
Packit 6c4009
	scale_u.d = 1.0;
Packit 6c4009
	scale_u.ieee.exponent += tval - (tval >> unsafe);
Packit 6c4009
Packit 6c4009
	/* 4. Approximate 2^x2 - 1, using a fourth-degree polynomial,
Packit 6c4009
	   with maximum error in [-2^-10-2^-30,2^-10+2^-30]
Packit 6c4009
	   less than 10^-19.  */
Packit 6c4009
Packit 6c4009
	x22 = (((.0096181293647031180
Packit 6c4009
		 * x + .055504110254308625)
Packit 6c4009
		* x + .240226506959100583)
Packit 6c4009
	       * x + .69314718055994495) * ex2_u.d;
Packit 6c4009
	math_opt_barrier (x22);
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
      /* 5. Return (2^x2-1) * 2^(t/512+e+ex) + 2^(t/512+e+ex).  */
Packit 6c4009
      result = x22 * x + ex2_u.d;
Packit 6c4009
Packit 6c4009
      if (!unsafe)
Packit 6c4009
	return result;
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  result *= scale_u.d;
Packit 6c4009
	  math_check_force_underflow_nonneg (result);
Packit 6c4009
	  return result;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    /* Return x, if x is a NaN or Inf; or overflow, otherwise.  */
Packit 6c4009
    return TWO1023 * x;
Packit 6c4009
}
Packit 6c4009
strong_alias (__ieee754_exp2, __exp2_finite)