< nwmcsween> nsz libm.h slow -> large
[libm] / src / math / nexttowardf.c
1 /* origin: FreeBSD /usr/src/lib/msun/src/s_nexttowardf.c */
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 #include "libm.h"
14
15 #if LD64
16 // FIXME
17 #elif LD80 || LD128
18 #define LDBL_INFNAN_EXP (LDBL_MAX_EXP * 2 - 1)
19
20 float nexttowardf(float x, long double y)
21 {
22         union IEEEl2bits uy;
23         volatile float t;
24         int32_t hx,ix;
25
26         GET_FLOAT_WORD(hx, x);
27         ix = hx & 0x7fffffff;  /* |x| */
28         uy.e = y;
29
30         if (ix > 0x7f800000 ||
31             (uy.bits.exp == LDBL_INFNAN_EXP &&
32              ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
33                 return x + y;  /* x or y is nan */
34         if (x == y)
35                 return (float)y;  /* x=y, return y */
36         if (ix == 0) {   /* x == 0 */
37                 SET_FLOAT_WORD(x, (uy.bits.sign<<31)|1); /* return +-minsubnormal */
38                 /* raise underflow flag */
39                 t = x*x;
40                 if (t == x)
41                         return t;
42                 return x;
43         }
44         if (hx >= 0 ^ x < y)  /* x -= ulp */
45                 hx -= 1;
46         else                  /* x += ulp */
47                 hx += 1;
48         ix = hx & 0x7f800000;
49         if (ix >= 0x7f800000)  /* overflow  */
50                 return x+x;
51         if (ix < 0x00800000) { /* underflow */
52                 /* raise underflow flag */
53                 t = x*x;
54                 if (t != x) {
55                         SET_FLOAT_WORD(x, hx);
56                         return x;
57                 }
58         }
59         SET_FLOAT_WORD(x, hx);
60         return x;
61 }
62 #endif