Blame sysdeps/ieee754/flt-32/k_rem_pio2f.c

Packit 6c4009
/* k_rem_pio2f.c -- float version of k_rem_pio2.c
Packit 6c4009
 * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
Packit 6c4009
 */
Packit 6c4009
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_pio2f.c,v 1.4 1995/05/10 20:46:28 jtc Exp $";
Packit 6c4009
#endif
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
/* In the float version, the input parameter x contains 8 bit
Packit 6c4009
   integers, not 24 bit integers.  113 bit precision is not supported.  */
Packit 6c4009
Packit 6c4009
static const int init_jk[] = {4,7,9}; /* initial value for jk */
Packit 6c4009
Packit 6c4009
static const float PIo2[] = {
Packit 6c4009
  1.5703125000e+00, /* 0x3fc90000 */
Packit 6c4009
  4.5776367188e-04, /* 0x39f00000 */
Packit 6c4009
  2.5987625122e-05, /* 0x37da0000 */
Packit 6c4009
  7.5437128544e-08, /* 0x33a20000 */
Packit 6c4009
  6.0026650317e-11, /* 0x2e840000 */
Packit 6c4009
  7.3896444519e-13, /* 0x2b500000 */
Packit 6c4009
  5.3845816694e-15, /* 0x27c20000 */
Packit 6c4009
  5.6378512969e-18, /* 0x22d00000 */
Packit 6c4009
  8.3009228831e-20, /* 0x1fc40000 */
Packit 6c4009
  3.2756352257e-22, /* 0x1bc60000 */
Packit 6c4009
  6.3331015649e-25, /* 0x17440000 */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static const float
Packit 6c4009
zero   = 0.0,
Packit 6c4009
one    = 1.0,
Packit 6c4009
two8   =  2.5600000000e+02, /* 0x43800000 */
Packit 6c4009
twon8  =  3.9062500000e-03; /* 0x3b800000 */
Packit 6c4009
Packit 6c4009
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, 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
	float 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)/8; if(jv<0) jv=0;
Packit 6c4009
	q0 =  e0-8*(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++) f[i] = (j<0)? zero : (float) ipio2[j];
Packit 6c4009
Packit 6c4009
    /* compute q[0],q[1],...q[jk] */
Packit 6c4009
	for (i=0;i<=jk;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
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
	    fw    =  (float)((int32_t)(twon8* z));
Packit 6c4009
	    iq[i] =  (int32_t)(z-two8*fw);
Packit 6c4009
	    z     =  q[j-1]+fw;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    /* compute n */
Packit 6c4009
	z  = __scalbnf(z,q0);		/* actual value of z */
Packit 6c4009
	z -= (float)8.0*__floorf(z*(float)0.125);	/* trim off integer >= 8 */
Packit 6c4009
	n  = (int32_t) z;
Packit 6c4009
	z -= (float)n;
Packit 6c4009
	ih = 0;
Packit 6c4009
	if(q0>0) {	/* need iq[jz-1] to determine n */
Packit 6c4009
	    i  = (iq[jz-1]>>(8-q0)); n += i;
Packit 6c4009
	    iq[jz-1] -= i<<(8-q0);
Packit 6c4009
	    ih = iq[jz-1]>>(7-q0);
Packit 6c4009
	}
Packit 6c4009
	else if(q0==0) ih = iq[jz-1]>>7;
Packit 6c4009
	else if(z>=(float)0.5) ih=2;
Packit 6c4009
Packit 6c4009
	if(ih>0) {	/* q > 0.5 */
Packit 6c4009
	    n += 1; carry = 0;
Packit 6c4009
	    for(i=0;i
Packit 6c4009
		j = iq[i];
Packit 6c4009
		if(carry==0) {
Packit 6c4009
		    if(j!=0) {
Packit 6c4009
			carry = 1; iq[i] = 0x100- j;
Packit 6c4009
		    }
Packit 6c4009
		} else  iq[i] = 0xff - j;
Packit 6c4009
	    }
Packit 6c4009
	    if(q0>0) {		/* rare case: chance is 1 in 12 */
Packit 6c4009
	        switch(q0) {
Packit 6c4009
	        case 1:
Packit 6c4009
		   iq[jz-1] &= 0x7f; break;
Packit 6c4009
		case 2:
Packit 6c4009
		   iq[jz-1] &= 0x3f; break;
Packit 6c4009
	        }
Packit 6c4009
	    }
Packit 6c4009
	    if(ih==2) {
Packit 6c4009
		z = one - z;
Packit 6c4009
		if(carry!=0) z -= __scalbnf(one,q0);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    /* check if recomputation is needed */
Packit 6c4009
	if(z==zero) {
Packit 6c4009
	    j = 0;
Packit 6c4009
	    for (i=jz-1;i>=jk;i--) j |= iq[i];
Packit 6c4009
	    if(j==0) { /* need recomputation */
Packit 6c4009
		/* On s390x gcc 6.1 -O3 produces the warning "array subscript is
Packit 6c4009
		   below array bounds [-Werror=array-bounds]".  Only
Packit 6c4009
		   __ieee754_rem_pio2f calls __kernel_rem_pio2f for normal
Packit 6c4009
		   numbers and |x| ~> 2^7*(pi/2).  Thus x can't be zero and
Packit 6c4009
		   ipio2 is not zero, too.  Thus not all iq[] values can't be
Packit 6c4009
		   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++);   /* 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
		    f[jx+i] = (float) ipio2[jv+i];
Packit 6c4009
		    for(j=0,fw=0.0;j<=jx;j++) 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==(float)0.0) {
Packit 6c4009
	    jz -= 1; q0 -= 8;
Packit 6c4009
	    while(iq[jz]==0) { jz--; q0-=8;}
Packit 6c4009
	} else { /* break z into 8-bit if necessary */
Packit 6c4009
	    z = __scalbnf(z,-q0);
Packit 6c4009
	    if(z>=two8) {
Packit 6c4009
		fw = (float)((int32_t)(twon8*z));
Packit 6c4009
		iq[jz] = (int32_t)(z-two8*fw);
Packit 6c4009
		jz += 1; q0 += 8;
Packit 6c4009
		iq[jz] = (int32_t) fw;
Packit 6c4009
	    } else iq[jz] = (int32_t) z ;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    /* convert integer "bit" chunk to floating-point value */
Packit 6c4009
	fw = __scalbnf(one,q0);
Packit 6c4009
	for(i=jz;i>=0;i--) {
Packit 6c4009
	    q[i] = fw*(float)iq[i]; fw*=twon8;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    /* compute PIo2[0,...,jp]*q[jz,...,0] */
Packit 6c4009
	for(i=jz;i>=0;i--) {
Packit 6c4009
	    for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) 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
	    case 0:
Packit 6c4009
		fw = 0.0;
Packit 6c4009
		for (i=jz;i>=0;i--) fw += fq[i];
Packit 6c4009
		y[0] = (ih==0)? fw: -fw;
Packit 6c4009
		break;
Packit 6c4009
	    case 1:
Packit 6c4009
	    case 2:;
Packit 6c4009
		float fv = 0.0;
Packit 6c4009
		for (i=jz;i>=0;i--) 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
Packit 6c4009
		   i686, warns that fq[0] may be used uninitialized.
Packit 6c4009
		   This is not possible because jz is always
Packit 6c4009
		   nonnegative when the above loop initializing fq is
Packit 6c4009
		   executed, because the result is never zero to full
Packit 6c4009
		   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++) 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
		    float 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
		    float 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--) fw += fq[i];
Packit 6c4009
		if(ih==0) {
Packit 6c4009
		    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
Packit 6c4009
		} else {
Packit 6c4009
		    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
Packit 6c4009
		}
Packit 6c4009
	}
Packit 6c4009
	return n&7;
Packit 6c4009
}