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