Import OpenBSD's libm (trunk, 4 July 2015) to a new vendor branch
[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
22 #include "math_private.h"
23
24 long double
25 nextafterl(long double x, long double y)
26 {
27         int32_t hx,hy,ix,iy;
28         u_int32_t lx,ly,esx,esy;
29
30         GET_LDOUBLE_WORDS(esx,hx,lx,x);
31         GET_LDOUBLE_WORDS(esy,hy,ly,y);
32         ix = esx&0x7fff;                /* |x| */
33         iy = esy&0x7fff;                /* |y| */
34
35         if (((ix==0x7fff)&&((hx&0x7fffffff|lx)!=0)) ||   /* x is nan */
36             ((iy==0x7fff)&&((hy&0x7fffffff|ly)!=0)))     /* y is nan */
37            return x+y;
38         if(x==y) return y;              /* x=y, return y */
39         if((ix|hx|lx)==0) {                     /* x == 0 */
40             volatile long double u;
41             SET_LDOUBLE_WORDS(x,esy&0x8000,0,1);/* return +-minsubnormal */
42             u = x;
43             u = u * u;                          /* raise underflow flag */
44             return x;
45         }
46         if(esx<0x8000) {                        /* x > 0 */
47             if(ix>iy||((ix==iy) && (hx>hy||((hx==hy)&&(lx>ly))))) {
48               /* x > y, x -= ulp */
49                 if(lx==0) {
50                     if ((hx&0x7fffffff)==0) esx -= 1;
51                     hx = (hx - 1) | (hx & 0x80000000);
52                 }
53                 lx -= 1;
54             } else {                            /* x < y, x += ulp */
55                 lx += 1;
56                 if(lx==0) {
57                     hx = (hx + 1) | (hx & 0x80000000);
58                     if ((hx&0x7fffffff)==0) esx += 1;
59                 }
60             }
61         } else {                                /* x < 0 */
62             if(esy>=0||(ix>iy||((ix==iy)&&(hx>hy||((hx==hy)&&(lx>ly)))))){
63               /* x < y, x -= ulp */
64                 if(lx==0) {
65                     if ((hx&0x7fffffff)==0) esx -= 1;
66                     hx = (hx - 1) | (hx & 0x80000000);
67                 }
68                 lx -= 1;
69             } else {                            /* x > y, x += ulp */
70                 lx += 1;
71                 if(lx==0) {
72                     hx = (hx + 1) | (hx & 0x80000000);
73                     if ((hx&0x7fffffff)==0) esx += 1;
74                 }
75             }
76         }
77         esy = esx&0x7fff;
78         if(esy==0x7fff) return x+x;             /* overflow  */
79         if(esy==0) {
80             volatile long double u = x*x;       /* underflow */
81             if(u==x) {
82                 SET_LDOUBLE_WORDS(x,esx,hx,lx);
83                 return x;
84             }
85         }
86         SET_LDOUBLE_WORDS(x,esx,hx,lx);
87         return x;
88 }
89
90 __strong_alias(nexttowardl, nextafterl);