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

Packit 6c4009
/* @(#)k_rem_pio2.c 5.1 93/09/24 */
Packit 6c4009
/*
Packit 6c4009
 * ====================================================
Packit 6c4009
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Developed at SunPro, a Sun Microsystems, Inc. business.
Packit 6c4009
 * Permission to use, copy, modify, and distribute this
Packit 6c4009
 * software is freely granted, provided that this notice
Packit 6c4009
 * is preserved.
Packit 6c4009
 * ====================================================
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#if defined(LIBM_SCCS) && !defined(lint)
Packit 6c4009
static char rcsid[] = "$NetBSD: k_rem_pio2.c,v 1.7 1995/05/10 20:46:25 jtc Exp $";
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
Packit 6c4009
 * double x[],y[]; int e0,nx,prec; int ipio2[];
Packit 6c4009
 *
Packit 6c4009
 * __kernel_rem_pio2 return the last three digits of N with
Packit 6c4009
 *		y = x - N*pi/2
Packit 6c4009
 * so that |y| < pi/2.
Packit 6c4009
 *
Packit 6c4009
 * The method is to compute the integer (mod 8) and fraction parts of
Packit 6c4009
 * (2/pi)*x without doing the full multiplication. In general we
Packit 6c4009
 * skip the part of the product that are known to be a huge integer (
Packit 6c4009
 * more accurately, = 0 mod 8 ). Thus the number of operations are
Packit 6c4009
 * independent of the exponent of the input.
Packit 6c4009
 *
Packit 6c4009
 * (2/pi) is represented by an array of 24-bit integers in ipio2[].
Packit 6c4009
 *
Packit 6c4009
 * Input parameters:
Packit 6c4009
 * 	x[]	The input value (must be positive) is broken into nx
Packit 6c4009
 *		pieces of 24-bit integers in double precision format.
Packit 6c4009
 *		x[i] will be the i-th 24 bit of x. The scaled exponent
Packit 6c4009
 *		of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
Packit 6c4009
 *		match x's up to 24 bits.
Packit 6c4009
 *
Packit 6c4009
 *		Example of breaking a double positive z into x[0]+x[1]+x[2]:
Packit 6c4009
 *			e0 = ilogb(z)-23
Packit 6c4009
 *			z  = scalbn(z,-e0)
Packit 6c4009
 *		for i = 0,1,2
Packit 6c4009
 *			x[i] = floor(z)
Packit 6c4009
 *			z    = (z-x[i])*2**24
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 *	y[]	ouput result in an array of double precision numbers.
Packit 6c4009
 *		The dimension of y[] is:
Packit 6c4009
 *			24-bit  precision	1
Packit 6c4009
 *			53-bit  precision	2
Packit 6c4009
 *			64-bit  precision	2
Packit 6c4009
 *			113-bit precision	3
Packit 6c4009
 *		The actual value is the sum of them. Thus for 113-bit
Packit 6c4009
 *		precision, one may have to do something like:
Packit 6c4009
 *
Packit 6c4009
 *		long double t,w,r_head, r_tail;
Packit 6c4009
 *		t = (long double)y[2] + (long double)y[1];
Packit 6c4009
 *		w = (long double)y[0];
Packit 6c4009
 *		r_head = t+w;
Packit 6c4009
 *		r_tail = w - (r_head - t);
Packit 6c4009
 *
Packit 6c4009
 *	e0	The exponent of x[0]
Packit 6c4009
 *
Packit 6c4009
 *	nx	dimension of x[]
Packit 6c4009
 *
Packit 6c4009
 *  	prec	an integer indicating the precision:
Packit 6c4009
 *			0	24  bits (single)
Packit 6c4009
 *			1	53  bits (double)
Packit 6c4009
 *			2	64  bits (extended)
Packit 6c4009
 *			3	113 bits (quad)
Packit 6c4009
 *
Packit 6c4009
 *	ipio2[]
Packit 6c4009
 *		integer array, contains the (24*i)-th to (24*i+23)-th
Packit 6c4009
 *		bit of 2/pi after binary point. The corresponding
Packit 6c4009
 *		floating value is
Packit 6c4009
 *
Packit 6c4009
 *			ipio2[i] * 2^(-24(i+1)).
Packit 6c4009
 *
Packit 6c4009
 * External function:
Packit 6c4009
 *	double scalbn(), floor();
Packit 6c4009
 *
Packit 6c4009
 *
Packit 6c4009
 * Here is the description of some local variables:
Packit 6c4009
 *
Packit 6c4009
 * 	jk	jk+1 is the initial number of terms of ipio2[] needed
Packit 6c4009
 *		in the computation. The recommended value is 2,3,4,
Packit 6c4009
 *		6 for single, double, extended,and quad.
Packit 6c4009
 *
Packit 6c4009
 * 	jz	local integer variable indicating the number of
Packit 6c4009
 *		terms of ipio2[] used.
Packit 6c4009
 *
Packit 6c4009
 *	jx	nx - 1
Packit 6c4009
 *
Packit 6c4009
 *	jv	index for pointing to the suitable ipio2[] for the
Packit 6c4009
 *		computation. In general, we want
Packit 6c4009
 *			( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
Packit 6c4009
 *		is an integer. Thus
Packit 6c4009
 *			e0-3-24*jv >= 0 or (e0-3)/24 >= jv
Packit 6c4009
 *		Hence jv = max(0,(e0-3)/24).
Packit 6c4009
 *
Packit 6c4009
 *	jp	jp+1 is the number of terms in PIo2[] needed, jp = jk.
Packit 6c4009
 *
Packit 6c4009
 * 	q[]	double array with integral value, representing the
Packit 6c4009
 *		24-bits chunk of the product of x and 2/pi.
Packit 6c4009
 *
Packit 6c4009
 *	q0	the corresponding exponent of q[0]. Note that the
Packit 6c4009
 *		exponent for q[i] would be q0-24*i.
Packit 6c4009
 *
Packit 6c4009
 *	PIo2[]	double precision array, obtained by cutting pi/2
Packit 6c4009
 *		into 24 bits chunks.
Packit 6c4009
 *
Packit 6c4009
 *	f[]	ipio2[] in floating point
Packit 6c4009
 *
Packit 6c4009
 *	iq[]	integer array by breaking up q[] in 24-bits chunk.
Packit 6c4009
 *
Packit 6c4009
 *	fq[]	final product of x*(2/pi) in fq[0],..,fq[jk]
Packit 6c4009
 *
Packit 6c4009
 *	ih	integer. If >0 it indicates q[] is >= 0.5, hence
Packit 6c4009
 *		it also indicates the *sign* of the result.
Packit 6c4009
 *
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Constants:
Packit 6c4009
 * The hexadecimal values are the intended ones for the following
Packit 6c4009
 * constants. The decimal values may be used, provided that the
Packit 6c4009
 * compiler will convert from decimal to binary accurately enough
Packit 6c4009
 * to produce the hexadecimal values shown.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <math-narrow-eval.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
Packit 6c4009
Packit 6c4009
static const double PIo2[] = {
Packit 6c4009
  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
Packit 6c4009
  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
Packit 6c4009
  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
Packit 6c4009
  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
Packit 6c4009
  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
Packit 6c4009
  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
Packit 6c4009
  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
Packit 6c4009
  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static const double
Packit 6c4009
  zero   = 0.0,
Packit 6c4009
  one    = 1.0,
Packit 6c4009
  two24  = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
Packit 6c4009
  twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__kernel_rem_pio2 (double *x, double *y, int e0, int nx, int prec,
Packit 6c4009
                   const int32_t *ipio2)
Packit 6c4009
{
Packit 6c4009
  int32_t jz, jx, jv, jp, jk, carry, n, iq[20], i, j, k, m, q0, ih;
Packit 6c4009
  double z, fw, f[20], fq[20], q[20];
Packit 6c4009
Packit 6c4009
  /* initialize jk*/
Packit 6c4009
  jk = init_jk[prec];
Packit 6c4009
  jp = jk;
Packit 6c4009
Packit 6c4009
  /* determine jx,jv,q0, note that 3>q0 */
Packit 6c4009
  jx = nx - 1;
Packit 6c4009
  jv = (e0 - 3) / 24; if (jv < 0)
Packit 6c4009
    jv = 0;
Packit 6c4009
  q0 = e0 - 24 * (jv + 1);
Packit 6c4009
Packit 6c4009
  /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
Packit 6c4009
  j = jv - jx; m = jx + jk;
Packit 6c4009
  for (i = 0; i <= m; i++, j++)
Packit 6c4009
    f[i] = (j < 0) ? zero : (double) ipio2[j];
Packit 6c4009
Packit 6c4009
  /* compute q[0],q[1],...q[jk] */
Packit 6c4009
  for (i = 0; i <= jk; i++)
Packit 6c4009
    {
Packit 6c4009
      for (j = 0, fw = 0.0; j <= jx; j++)
Packit 6c4009
	fw += x[j] * f[jx + i - j];
Packit 6c4009
      q[i] = fw;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  jz = jk;
Packit 6c4009
recompute:
Packit 6c4009
  /* distill q[] into iq[] reversingly */
Packit 6c4009
  for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--)
Packit 6c4009
    {
Packit 6c4009
      fw = (double) ((int32_t) (twon24 * z));
Packit 6c4009
      iq[i] = (int32_t) (z - two24 * fw);
Packit 6c4009
      z = q[j - 1] + fw;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* compute n */
Packit 6c4009
  z = __scalbn (z, q0);                 /* actual value of z */
Packit 6c4009
  z -= 8.0 * __floor (z * 0.125);               /* trim off integer >= 8 */
Packit 6c4009
  n = (int32_t) z;
Packit 6c4009
  z -= (double) n;
Packit 6c4009
  ih = 0;
Packit 6c4009
  if (q0 > 0)           /* need iq[jz-1] to determine n */
Packit 6c4009
    {
Packit 6c4009
      i = (iq[jz - 1] >> (24 - q0)); n += i;
Packit 6c4009
      iq[jz - 1] -= i << (24 - q0);
Packit 6c4009
      ih = iq[jz - 1] >> (23 - q0);
Packit 6c4009
    }
Packit 6c4009
  else if (q0 == 0)
Packit 6c4009
    ih = iq[jz - 1] >> 23;
Packit 6c4009
  else if (z >= 0.5)
Packit 6c4009
    ih = 2;
Packit 6c4009
Packit 6c4009
  if (ih > 0)           /* q > 0.5 */
Packit 6c4009
    {
Packit 6c4009
      n += 1; carry = 0;
Packit 6c4009
      for (i = 0; i < jz; i++)          /* compute 1-q */
Packit 6c4009
	{
Packit 6c4009
	  j = iq[i];
Packit 6c4009
	  if (carry == 0)
Packit 6c4009
	    {
Packit 6c4009
	      if (j != 0)
Packit 6c4009
		{
Packit 6c4009
		  carry = 1; iq[i] = 0x1000000 - j;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    iq[i] = 0xffffff - j;
Packit 6c4009
	}
Packit 6c4009
      if (q0 > 0)               /* rare case: chance is 1 in 12 */
Packit 6c4009
	{
Packit 6c4009
	  switch (q0)
Packit 6c4009
	    {
Packit 6c4009
	    case 1:
Packit 6c4009
	      iq[jz - 1] &= 0x7fffff; break;
Packit 6c4009
	    case 2:
Packit 6c4009
	      iq[jz - 1] &= 0x3fffff; break;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      if (ih == 2)
Packit 6c4009
	{
Packit 6c4009
	  z = one - z;
Packit 6c4009
	  if (carry != 0)
Packit 6c4009
	    z -= __scalbn (one, q0);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* check if recomputation is needed */
Packit 6c4009
  if (z == zero)
Packit 6c4009
    {
Packit 6c4009
      j = 0;
Packit 6c4009
      for (i = jz - 1; i >= jk; i--)
Packit 6c4009
	j |= iq[i];
Packit 6c4009
      if (j == 0)      /* need recomputation */
Packit 6c4009
	{
Packit 6c4009
	  /* On s390x gcc 6.1 -O3 produces the warning "array subscript is below
Packit 6c4009
	     array bounds [-Werror=array-bounds]".  Only __ieee754_rem_pio2l
Packit 6c4009
	     calls __kernel_rem_pio2 for normal numbers and |x| > pi/4 in case
Packit 6c4009
	     of ldbl-96 and |x| > 3pi/4 in case of ldbl-128[ibm].
Packit 6c4009
	     Thus x can't be zero and ipio2 is not zero, too.  Thus not all iq[]
Packit 6c4009
	     values can't be zero.  */
Packit 6c4009
	  DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
	  DIAG_IGNORE_NEEDS_COMMENT (6.1, "-Warray-bounds");
Packit 6c4009
	  for (k = 1; iq[jk - k] == 0; k++)
Packit 6c4009
	    ;                               /* k = no. of terms needed */
Packit 6c4009
	  DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
Packit 6c4009
	  for (i = jz + 1; i <= jz + k; i++) /* add q[jz+1] to q[jz+k] */
Packit 6c4009
	    {
Packit 6c4009
	      f[jx + i] = (double) ipio2[jv + i];
Packit 6c4009
	      for (j = 0, fw = 0.0; j <= jx; j++)
Packit 6c4009
		fw += x[j] * f[jx + i - j];
Packit 6c4009
	      q[i] = fw;
Packit 6c4009
	    }
Packit 6c4009
	  jz += k;
Packit 6c4009
	  goto recompute;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* chop off zero terms */
Packit 6c4009
  if (z == 0.0)
Packit 6c4009
    {
Packit 6c4009
      jz -= 1; q0 -= 24;
Packit 6c4009
      while (iq[jz] == 0)
Packit 6c4009
	{
Packit 6c4009
	  jz--; q0 -= 24;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else           /* break z into 24-bit if necessary */
Packit 6c4009
    {
Packit 6c4009
      z = __scalbn (z, -q0);
Packit 6c4009
      if (z >= two24)
Packit 6c4009
	{
Packit 6c4009
	  fw = (double) ((int32_t) (twon24 * z));
Packit 6c4009
	  iq[jz] = (int32_t) (z - two24 * fw);
Packit 6c4009
	  jz += 1; q0 += 24;
Packit 6c4009
	  iq[jz] = (int32_t) fw;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	iq[jz] = (int32_t) z;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* convert integer "bit" chunk to floating-point value */
Packit 6c4009
  fw = __scalbn (one, q0);
Packit 6c4009
  for (i = jz; i >= 0; i--)
Packit 6c4009
    {
Packit 6c4009
      q[i] = fw * (double) iq[i]; fw *= twon24;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* compute PIo2[0,...,jp]*q[jz,...,0] */
Packit 6c4009
  for (i = jz; i >= 0; i--)
Packit 6c4009
    {
Packit 6c4009
      for (fw = 0.0, k = 0; k <= jp && k <= jz - i; k++)
Packit 6c4009
	fw += PIo2[k] * q[i + k];
Packit 6c4009
      fq[jz - i] = fw;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* compress fq[] into y[] */
Packit 6c4009
  switch (prec)
Packit 6c4009
    {
Packit 6c4009
    case 0:
Packit 6c4009
      fw = 0.0;
Packit 6c4009
      for (i = jz; i >= 0; i--)
Packit 6c4009
	fw += fq[i];
Packit 6c4009
      y[0] = (ih == 0) ? fw : -fw;
Packit 6c4009
      break;
Packit 6c4009
    case 1:
Packit 6c4009
    case 2:;
Packit 6c4009
      double fv = 0.0;
Packit 6c4009
      for (i = jz; i >= 0; i--)
Packit 6c4009
	fv = math_narrow_eval (fv + fq[i]);
Packit 6c4009
      y[0] = (ih == 0) ? fv : -fv;
Packit 6c4009
      /* GCC mainline (to be GCC 9), as of 2018-05-22 on i686, warns
Packit 6c4009
	 that fq[0] may be used uninitialized.  This is not possible
Packit 6c4009
	 because jz is always nonnegative when the above loop
Packit 6c4009
	 initializing fq is executed, because the result is never zero
Packit 6c4009
	 to full precision (this function is not called for zero
Packit 6c4009
	 arguments).  */
Packit 6c4009
      DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
      DIAG_IGNORE_NEEDS_COMMENT (9, "-Wmaybe-uninitialized");
Packit 6c4009
      fv = math_narrow_eval (fq[0] - fv);
Packit 6c4009
      DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
      for (i = 1; i <= jz; i++)
Packit 6c4009
	fv = math_narrow_eval (fv + fq[i]);
Packit 6c4009
      y[1] = (ih == 0) ? fv : -fv;
Packit 6c4009
      break;
Packit 6c4009
    case 3:             /* painful */
Packit 6c4009
      for (i = jz; i > 0; i--)
Packit 6c4009
	{
Packit 6c4009
	  double fv = math_narrow_eval (fq[i - 1] + fq[i]);
Packit 6c4009
	  fq[i] += fq[i - 1] - fv;
Packit 6c4009
	  fq[i - 1] = fv;
Packit 6c4009
	}
Packit 6c4009
      for (i = jz; i > 1; i--)
Packit 6c4009
	{
Packit 6c4009
	  double fv = math_narrow_eval (fq[i - 1] + fq[i]);
Packit 6c4009
	  fq[i] += fq[i - 1] - fv;
Packit 6c4009
	  fq[i - 1] = fv;
Packit 6c4009
	}
Packit 6c4009
      for (fw = 0.0, i = jz; i >= 2; i--)
Packit 6c4009
	fw += fq[i];
Packit 6c4009
      if (ih == 0)
Packit 6c4009
	{
Packit 6c4009
	  y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return n & 7;
Packit 6c4009
}