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 
__nextafterl(long double x,long double y)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)
107