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

Packit 6c4009
/* s_nextafterl.c -- long double version of s_nextafter.c.
Packit 6c4009
 * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
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: $";
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* IEEE functions
Packit 6c4009
 *	nextafterl(x,y)
Packit 6c4009
 *	return the next machine floating-point number of x in the
Packit 6c4009
 *	direction toward y.
Packit 6c4009
 *   Special cases:
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <float.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <math-barriers.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <math_ldbl_opt.h>
Packit 6c4009
Packit 6c4009
long double __nextafterl(long double x, long double y)
Packit 6c4009
{
Packit 6c4009
	int64_t hx, hy, ihx, ihy, lx;
Packit 6c4009
	double xhi, xlo, yhi;
Packit 6c4009
Packit 6c4009
	ldbl_unpack (x, &xhi, &xlo;;
Packit 6c4009
	EXTRACT_WORDS64 (hx, xhi);
Packit 6c4009
	EXTRACT_WORDS64 (lx, xlo);
Packit 6c4009
	yhi = ldbl_high (y);
Packit 6c4009
	EXTRACT_WORDS64 (hy, yhi);
Packit 6c4009
	ihx = hx&0x7fffffffffffffffLL;		/* |hx| */
Packit 6c4009
	ihy = hy&0x7fffffffffffffffLL;		/* |hy| */
Packit 6c4009
Packit 6c4009
	if((ihx>0x7ff0000000000000LL) ||	/* x is nan */
Packit 6c4009
	   (ihy>0x7ff0000000000000LL))		/* y is nan */
Packit 6c4009
	    return x+y; /* signal the nan */
Packit 6c4009
	if(x==y)
Packit 6c4009
	    return y;		/* x=y, return y */
Packit 6c4009
	if(ihx == 0) {				/* x == 0 */
Packit 6c4009
	    long double u;			/* return +-minsubnormal */
Packit 6c4009
	    hy = (hy & 0x8000000000000000ULL) | 1;
Packit 6c4009
	    INSERT_WORDS64 (yhi, hy);
Packit 6c4009
	    x = yhi;
Packit 6c4009
	    u = math_opt_barrier (x);
Packit 6c4009
	    u = u * u;
Packit 6c4009
	    math_force_eval (u);		/* raise underflow flag */
Packit 6c4009
	    return x;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	long double u;
Packit 6c4009
	if(x > y) {	/* x > y, x -= ulp */
Packit 6c4009
	    /* This isn't the largest magnitude correctly rounded
Packit 6c4009
	       long double as you can see from the lowest mantissa
Packit 6c4009
	       bit being zero.  It is however the largest magnitude
Packit 6c4009
	       long double with a 106 bit mantissa, and nextafterl
Packit 6c4009
	       is insane with variable precision.  So to make
Packit 6c4009
	       nextafterl sane we assume 106 bit precision.  */
Packit 6c4009
	    if((hx==0xffefffffffffffffLL)&&(lx==0xfc8ffffffffffffeLL)) {
Packit 6c4009
	      u = x+x;	/* overflow, return -inf */
Packit 6c4009
	      math_force_eval (u);
Packit 6c4009
	      __set_errno (ERANGE);
Packit 6c4009
	      return y;
Packit 6c4009
	    }
Packit 6c4009
	    if (hx >= 0x7ff0000000000000LL) {
Packit 6c4009
	      u = 0x1.fffffffffffff7ffffffffffff8p+1023L;
Packit 6c4009
	      return u;
Packit 6c4009
	    }
Packit 6c4009
	    if(ihx <= 0x0360000000000000LL) {  /* x <= LDBL_MIN */
Packit 6c4009
	      u = math_opt_barrier (x);
Packit 6c4009
	      x -= LDBL_TRUE_MIN;
Packit 6c4009
	      if (ihx < 0x0360000000000000LL
Packit 6c4009
		  || (hx > 0 && lx <= 0)
Packit 6c4009
		  || (hx < 0 && lx > 1)) {
Packit 6c4009
		u = u * u;
Packit 6c4009
		math_force_eval (u);		/* raise underflow flag */
Packit 6c4009
		__set_errno (ERANGE);
Packit 6c4009
	      }
Packit 6c4009
	      /* Avoid returning -0 in FE_DOWNWARD mode.  */
Packit 6c4009
	      if (x == 0.0L)
Packit 6c4009
		return 0.0L;
Packit 6c4009
	      return x;
Packit 6c4009
	    }
Packit 6c4009
	    /* If the high double is an exact power of two and the low
Packit 6c4009
	       double is the opposite sign, then 1ulp is one less than
Packit 6c4009
	       what we might determine from the high double.  Similarly
Packit 6c4009
	       if X is an exact power of two, and positive, because
Packit 6c4009
	       making it a little smaller will result in the exponent
Packit 6c4009
	       decreasing by one and normalisation of the mantissa.   */
Packit 6c4009
	    if ((hx & 0x000fffffffffffffLL) == 0
Packit 6c4009
		&& ((lx != 0 && (hx ^ lx) < 0)
Packit 6c4009
		    || (lx == 0 && hx >= 0)))
Packit 6c4009
	      ihx -= 1LL << 52;
Packit 6c4009
	    if (ihx < (106LL << 52)) { /* ulp will denormal */
Packit 6c4009
	      INSERT_WORDS64 (yhi, ihx & (0x7ffLL<<52));
Packit 6c4009
	      u = yhi * 0x1p-105;
Packit 6c4009
	    } else {
Packit 6c4009
	      INSERT_WORDS64 (yhi, (ihx & (0x7ffLL<<52))-(105LL<<52));
Packit 6c4009
	      u = yhi;
Packit 6c4009
	    }
Packit 6c4009
	    return x - u;
Packit 6c4009
	} else {				/* x < y, x += ulp */
Packit 6c4009
	    if((hx==0x7fefffffffffffffLL)&&(lx==0x7c8ffffffffffffeLL)) {
Packit 6c4009
	      u = x+x;	/* overflow, return +inf */
Packit 6c4009
	      math_force_eval (u);
Packit 6c4009
	      __set_errno (ERANGE);
Packit 6c4009
	      return y;
Packit 6c4009
	    }
Packit 6c4009
	    if ((uint64_t) hx >= 0xfff0000000000000ULL) {
Packit 6c4009
	      u = -0x1.fffffffffffff7ffffffffffff8p+1023L;
Packit 6c4009
	      return u;
Packit 6c4009
	    }
Packit 6c4009
	    if(ihx <= 0x0360000000000000LL) {  /* x <= LDBL_MIN */
Packit 6c4009
	      u = math_opt_barrier (x);
Packit 6c4009
	      x += LDBL_TRUE_MIN;
Packit 6c4009
	      if (ihx < 0x0360000000000000LL
Packit 6c4009
		  || (hx > 0 && lx < 0 && lx != 0x8000000000000001LL)
Packit 6c4009
		  || (hx < 0 && lx >= 0)) {
Packit 6c4009
		u = u * u;
Packit 6c4009
		math_force_eval (u);		/* raise underflow flag */
Packit 6c4009
		__set_errno (ERANGE);
Packit 6c4009
	      }
Packit 6c4009
	      if (x == 0.0L)	/* handle negative LDBL_TRUE_MIN case */
Packit 6c4009
		x = -0.0L;
Packit 6c4009
	      return x;
Packit 6c4009
	    }
Packit 6c4009
	    /* If the high double is an exact power of two and the low
Packit 6c4009
	       double is the opposite sign, then 1ulp is one less than
Packit 6c4009
	       what we might determine from the high double.  Similarly
Packit 6c4009
	       if X is an exact power of two, and negative, because
Packit 6c4009
	       making it a little larger will result in the exponent
Packit 6c4009
	       decreasing by one and normalisation of the mantissa.   */
Packit 6c4009
	    if ((hx & 0x000fffffffffffffLL) == 0
Packit 6c4009
		&& ((lx != 0 && (hx ^ lx) < 0)
Packit 6c4009
		    || (lx == 0 && hx < 0)))
Packit 6c4009
	      ihx -= 1LL << 52;
Packit 6c4009
	    if (ihx < (106LL << 52)) { /* ulp will denormal */
Packit 6c4009
	      INSERT_WORDS64 (yhi, ihx & (0x7ffLL<<52));
Packit 6c4009
	      u = yhi * 0x1p-105;
Packit 6c4009
	    } else {
Packit 6c4009
	      INSERT_WORDS64 (yhi, (ihx & (0x7ffLL<<52))-(105LL<<52));
Packit 6c4009
	      u = yhi;
Packit 6c4009
	    }
Packit 6c4009
	    return x + u;
Packit 6c4009
	}
Packit 6c4009
}
Packit 6c4009
strong_alias (__nextafterl, __nexttowardl)
Packit 6c4009
long_double_symbol (libm, __nextafterl, nextafterl);
Packit 6c4009
long_double_symbol (libm, __nexttowardl, nexttowardl);