Blame sysdeps/ieee754/ldbl-128ibm/e_fmodl.c

Packit 6c4009
/* e_fmodl.c -- long double version of e_fmod.c.
Packit 6c4009
 * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
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
/*
Packit 6c4009
 * __ieee754_fmodl(x,y)
Packit 6c4009
 * Return x mod y in exact arithmetic
Packit 6c4009
 * Method: shift and subtract
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <ieee754.h>
Packit 6c4009
Packit 6c4009
static const long double one = 1.0, Zero[] = {0.0, -0.0,};
Packit 6c4009
Packit 6c4009
long double
Packit 6c4009
__ieee754_fmodl (long double x, long double y)
Packit 6c4009
{
Packit 6c4009
	int64_t hx, hy, hz, sx, sy;
Packit 6c4009
	uint64_t lx, ly, lz;
Packit 6c4009
	int n, ix, iy;
Packit 6c4009
	double xhi, xlo, yhi, ylo;
Packit 6c4009
Packit 6c4009
	ldbl_unpack (x, &xhi, &xlo;;
Packit 6c4009
	EXTRACT_WORDS64 (hx, xhi);
Packit 6c4009
	EXTRACT_WORDS64 (lx, xlo);
Packit 6c4009
	ldbl_unpack (y, &yhi, &ylo);
Packit 6c4009
	EXTRACT_WORDS64 (hy, yhi);
Packit 6c4009
	EXTRACT_WORDS64 (ly, ylo);
Packit 6c4009
	sx = hx&0x8000000000000000ULL;		/* sign of x */
Packit 6c4009
	hx ^= sx;				/* |x| */
Packit 6c4009
	sy = hy&0x8000000000000000ULL;		/* sign of y */
Packit 6c4009
	hy ^= sy;				/* |y| */
Packit 6c4009
Packit 6c4009
    /* purge off exception values */
Packit 6c4009
	if(__builtin_expect(hy==0 ||
Packit 6c4009
			    (hx>=0x7ff0000000000000LL)|| /* y=0,or x not finite */
Packit 6c4009
			    (hy>0x7ff0000000000000LL),0))	/* or y is NaN */
Packit 6c4009
	    return (x*y)/(x*y);
Packit 6c4009
	if (__glibc_unlikely (hx <= hy))
Packit 6c4009
	  {
Packit 6c4009
	    /* If |x| < |y| return x.  */
Packit 6c4009
	    if (hx < hy)
Packit 6c4009
	      return x;
Packit 6c4009
	    /* At this point the absolute value of the high doubles of
Packit 6c4009
	       x and y must be equal.  */
Packit 6c4009
	    if ((lx & 0x7fffffffffffffffLL) == 0
Packit 6c4009
		&& (ly & 0x7fffffffffffffffLL) == 0)
Packit 6c4009
	      /* Both low parts are zero.  The result should be an
Packit 6c4009
		 appropriately signed zero, but the subsequent logic
Packit 6c4009
		 could treat them as unequal, depending on the signs
Packit 6c4009
		 of the low parts.  */
Packit 6c4009
	      return Zero[(uint64_t) sx >> 63];
Packit 6c4009
	    /* If the low double of y is the same sign as the high
Packit 6c4009
	       double of y (ie. the low double increases |y|)...  */
Packit 6c4009
	    if (((ly ^ sy) & 0x8000000000000000LL) == 0
Packit 6c4009
		/* ... then a different sign low double to high double
Packit 6c4009
		   for x or same sign but lower magnitude...  */
Packit 6c4009
		&& (int64_t) (lx ^ sx) < (int64_t) (ly ^ sy))
Packit 6c4009
	      /* ... means |x| < |y|.  */
Packit 6c4009
	      return x;
Packit 6c4009
	    /* If the low double of x differs in sign to the high
Packit 6c4009
	       double of x (ie. the low double decreases |x|)...  */
Packit 6c4009
	    if (((lx ^ sx) & 0x8000000000000000LL) != 0
Packit 6c4009
		/* ... then a different sign low double to high double
Packit 6c4009
		   for y with lower magnitude (we've already caught
Packit 6c4009
		   the same sign for y case above)...  */
Packit 6c4009
		&& (int64_t) (lx ^ sx) > (int64_t) (ly ^ sy))
Packit 6c4009
	      /* ... means |x| < |y|.  */
Packit 6c4009
	      return x;
Packit 6c4009
	    /* If |x| == |y| return x*0.  */
Packit 6c4009
	    if ((lx ^ sx) == (ly ^ sy))
Packit 6c4009
	      return Zero[(uint64_t) sx >> 63];
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    /* Make the IBM extended format 105 bit mantissa look like the ieee854 112
Packit 6c4009
       bit mantissa so the following operations will give the correct
Packit 6c4009
       result.  */
Packit 6c4009
	ldbl_extract_mantissa(&hx, &lx, &ix, x);
Packit 6c4009
	ldbl_extract_mantissa(&hy, &ly, &iy, y);
Packit 6c4009
Packit 6c4009
	if (__glibc_unlikely (ix == -IEEE754_DOUBLE_BIAS))
Packit 6c4009
	  {
Packit 6c4009
	    /* subnormal x, shift x to normal.  */
Packit 6c4009
	    while ((hx & (1LL << 48)) == 0)
Packit 6c4009
	      {
Packit 6c4009
		hx = (hx << 1) | (lx >> 63);
Packit 6c4009
		lx = lx << 1;
Packit 6c4009
		ix -= 1;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	if (__glibc_unlikely (iy == -IEEE754_DOUBLE_BIAS))
Packit 6c4009
	  {
Packit 6c4009
	    /* subnormal y, shift y to normal.  */
Packit 6c4009
	    while ((hy & (1LL << 48)) == 0)
Packit 6c4009
	      {
Packit 6c4009
		hy = (hy << 1) | (ly >> 63);
Packit 6c4009
		ly = ly << 1;
Packit 6c4009
		iy -= 1;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
    /* fix point fmod */
Packit 6c4009
	n = ix - iy;
Packit 6c4009
	while(n--) {
Packit 6c4009
	    hz=hx-hy;lz=lx-ly; if(lx
Packit 6c4009
	    if(hz<0){hx = hx+hx+(lx>>63); lx = lx+lx;}
Packit 6c4009
	    else {
Packit 6c4009
		if((hz|lz)==0)		/* return sign(x)*0 */
Packit 6c4009
		    return Zero[(uint64_t)sx>>63];
Packit 6c4009
		hx = hz+hz+(lz>>63); lx = lz+lz;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
	hz=hx-hy;lz=lx-ly; if(lx
Packit 6c4009
	if(hz>=0) {hx=hz;lx=lz;}
Packit 6c4009
Packit 6c4009
    /* convert back to floating value and restore the sign */
Packit 6c4009
	if((hx|lx)==0)			/* return sign(x)*0 */
Packit 6c4009
	    return Zero[(uint64_t)sx>>63];
Packit 6c4009
	while(hx<0x0001000000000000LL) {	/* normalize x */
Packit 6c4009
	    hx = hx+hx+(lx>>63); lx = lx+lx;
Packit 6c4009
	    iy -= 1;
Packit 6c4009
	}
Packit 6c4009
	if(__builtin_expect(iy>= -1022,0)) {	/* normalize output */
Packit 6c4009
	    x = ldbl_insert_mantissa((sx>>63), iy, hx, lx);
Packit 6c4009
	} else {		/* subnormal output */
Packit 6c4009
	    n = -1022 - iy;
Packit 6c4009
	    /* We know 1 <= N <= 52, and that there are no nonzero
Packit 6c4009
	       bits in places below 2^-1074.  */
Packit 6c4009
	    lx = (lx >> n) | ((uint64_t) hx << (64 - n));
Packit 6c4009
	    hx >>= n;
Packit 6c4009
	    x = ldbl_insert_mantissa((sx>>63), -1023, hx, lx);
Packit 6c4009
	    x *= one;		/* create necessary signal */
Packit 6c4009
	}
Packit 6c4009
	return x;		/* exact output */
Packit 6c4009
}
Packit 6c4009
strong_alias (__ieee754_fmodl, __fmodl_finite)