first commit of the new libm!
[musl] / src / math / ceill.c
1 /* origin: FreeBSD /usr/src/lib/msun/src/s_ceill.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  * ceill(x)
14  * Return x rounded toward -inf to integral value
15  * Method:
16  *      Bit twiddling.
17  * Exception:
18  *      Inexact flag raised if x not equal to ceill(x).
19  */
20
21 #include "libm.h"
22
23 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
24 long double ceill(long double x)
25 {
26         return ceil(x);
27 }
28 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
29
30 #ifdef LDBL_IMPLICIT_NBIT
31 #define MANH_SIZE       (LDBL_MANH_SIZE + 1)
32 #define INC_MANH(u, c)  do {                                    \
33         uint64_t o = u.bits.manh;                               \
34         u.bits.manh += (c);                                     \
35         if (u.bits.manh < o)                                    \
36                 u.bits.exp++;                                   \
37 } while (0)
38 #else
39 #define MANH_SIZE       LDBL_MANH_SIZE
40 #define INC_MANH(u, c)  do {                                    \
41         uint64_t o = u.bits.manh;                               \
42         u.bits.manh += (c);                                     \
43         if (u.bits.manh < o) {                                  \
44                 u.bits.exp++;                                   \
45                 u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1);    \
46         }                                                       \
47 } while (0)
48 #endif
49
50 static const long double huge = 1.0e300;
51
52 long double
53 ceill(long double x)
54 {
55         union IEEEl2bits u = { .e = x };
56         int e = u.bits.exp - LDBL_MAX_EXP + 1;
57
58         if (e < MANH_SIZE - 1) {
59                 if (e < 0) {
60                         /* raise inexact if x != 0 */
61                         if (huge + x > 0.0)
62                                 if (u.bits.exp > 0 ||
63                                         (u.bits.manh | u.bits.manl) != 0)
64                                         u.e = u.bits.sign ? -0.0 : 1.0;
65                 } else {
66                         uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
67                         if (((u.bits.manh & m) | u.bits.manl) == 0)
68                                 return x;  /* x is integral */
69                         if (!u.bits.sign) {
70 #ifdef LDBL_IMPLICIT_NBIT
71                                 if (e == 0)
72                                         u.bits.exp++;
73                                 else
74 #endif
75                                 INC_MANH(u, 1llu << (MANH_SIZE - e - 1));
76                         }
77                         /* raise inexact flag */
78                         if (huge + x > 0.0) {
79                                 u.bits.manh &= ~m;
80                                 u.bits.manl = 0;
81                         }
82                 }
83         } else if (e < LDBL_MANT_DIG - 1) {
84                 uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
85                 if ((u.bits.manl & m) == 0)
86                         return x;  /* x is integral */
87                 if (!u.bits.sign) {
88                         if (e == MANH_SIZE - 1)
89                                 INC_MANH(u, 1);
90                         else {
91                                 uint64_t o = u.bits.manl;
92                                 u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1);
93                                 if (u.bits.manl < o)    /* got a carry */
94                                         INC_MANH(u, 1);
95                         }
96                 }
97                 /* raise inexact flag */
98                 if (huge + x > 0.0)
99                         u.bits.manl &= ~m;
100         }
101         return u.e;
102 }
103 #endif