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