1  /* s_nextafterl.c -- long double version of s_nextafter.c.
       2   */
       3  
       4  /*
       5   * ====================================================
       6   * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
       7   *
       8   * Developed at SunPro, a Sun Microsystems, Inc. business.
       9   * Permission to use, copy, modify, and distribute this
      10   * software is freely granted, provided that this notice
      11   * is preserved.
      12   * ====================================================
      13   */
      14  
      15  #if defined(LIBM_SCCS) && !defined(lint)
      16  static char rcsid[] = "$NetBSD: $";
      17  #endif
      18  
      19  /* IEEE functions
      20   *	nextafterl(x,y)
      21   *	return the next machine floating-point number of x in the
      22   *	direction toward y.
      23   *   Special cases:
      24   */
      25  
      26  #include <errno.h>
      27  #include <math.h>
      28  #include <math-barriers.h>
      29  #include <math_private.h>
      30  
      31  long double __nextafterl(long double x, long double y)
      32  {
      33  	int32_t ix,iy,esx,esy;
      34  	uint32_t hx,hy,lx,ly;
      35  
      36  	GET_LDOUBLE_WORDS(esx,hx,lx,x);
      37  	GET_LDOUBLE_WORDS(esy,hy,ly,y);
      38  	ix = esx&0x7fff;		/* |x| */
      39  	iy = esy&0x7fff;		/* |y| */
      40  
      41  	if(((ix==0x7fff)&&((hx&0x7fffffff)|lx)!=0) ||   /* x is nan */
      42  	   ((iy==0x7fff)&&((hy&0x7fffffff)|ly)!=0))     /* y is nan */
      43  	   return x+y;
      44  	if(x==y) return y;		/* x=y, return y */
      45  	if((ix|hx|lx)==0) {			/* x == 0 */
      46  	    SET_LDOUBLE_WORDS(x,esy&0x8000,0,1);/* return +-minsubnormal */
      47  	    y = x*x;
      48  	    math_force_eval (y);		/* raise underflow flag */
      49  	    return x;
      50  	}
      51  	if(esx>=0) {			/* x > 0 */
      52  	    if(esx>esy||((esx==esy) && (hx>hy||((hx==hy)&&(lx>ly))))) {
      53  	      /* x > y, x -= ulp */
      54  		if(lx==0) {
      55  		    if (ix != 0 && hx == 0x80000000) hx = 0;
      56  		    if (hx==0) esx -= 1;
      57  		    hx -= 1;
      58  		}
      59  		lx -= 1;
      60  	    } else {				/* x < y, x += ulp */
      61  		lx += 1;
      62  		if(lx==0) {
      63  		    hx += 1;
      64  		    if (hx==0) {
      65  			hx = 0x80000000;
      66  			esx += 1;
      67  		    }
      68  		}
      69  	    }
      70  	} else {				/* x < 0 */
      71  	    if(esy>=0||esx>esy||((esx==esy) && (hx>hy||((hx==hy)&&(lx>ly))))){
      72  	      /* x < y, x -= ulp */
      73  		if(lx==0) {
      74  		    if (ix != 0 && hx == 0x80000000) hx = 0;
      75  		    if (hx==0) esx -= 1;
      76  		    hx -= 1;
      77  		}
      78  		lx -= 1;
      79  	    } else {				/* x > y, x += ulp */
      80  		lx += 1;
      81  		if(lx==0) {
      82  		    hx += 1;
      83  		    if (hx==0) {
      84  			hx = 0x80000000;
      85  			esx += 1;
      86  		    }
      87  		}
      88  	    }
      89  	}
      90  	esy = esx&0x7fff;
      91  	if(esy==0x7fff) {
      92  	    long double u = x + x;	/* overflow  */
      93  	    math_force_eval (u);
      94  	    __set_errno (ERANGE);
      95  	}
      96  	if(esy==0 && (hx & 0x80000000) == 0) { /* underflow */
      97  	    y = x*x;
      98  	    math_force_eval (y);		/* raise underflow flag */
      99  	    __set_errno (ERANGE);
     100  	}
     101  	SET_LDOUBLE_WORDS(x,esx,hx,lx);
     102  	return x;
     103  }
     104  weak_alias (__nextafterl, nextafterl)
     105  strong_alias (__nextafterl, __nexttowardl)
     106  weak_alias (__nextafterl, nexttowardl)