math: fix tgamma to raise underflow for large negative values
[oweals/musl.git] / src / math / floorl.c
1 /* origin: FreeBSD /usr/src/lib/msun/src/s_floorl.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  * floorl(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 floorl(x).
19  */
20
21 #include "libm.h"
22
23 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
24 long double floorl(long double x)
25 {
26         return floor(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 floorl(long double x)
53 {
54         union IEEEl2bits u = { .e = x };
55         int e = u.bits.exp - LDBL_MAX_EXP + 1;
56
57         if (e < MANH_SIZE - 1) {
58                 if (e < 0) {
59                         /* raise inexact if x != 0 */
60                         if (huge + x > 0.0)
61                                 if (u.bits.exp > 0 ||
62                                     (u.bits.manh | u.bits.manl) != 0)
63                                         u.e = u.bits.sign ? -1.0 : 0.0;
64                 } else {
65                         uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
66                         if (((u.bits.manh & m) | u.bits.manl) == 0)
67                                 return x;  /* x is integral */
68                         if (u.bits.sign) {
69 #ifdef LDBL_IMPLICIT_NBIT
70                                 if (e == 0)
71                                         u.bits.exp++;
72                                 else
73 #endif
74                                 INC_MANH(u, 1llu << (MANH_SIZE - e - 1));
75                         }
76                         /* raise inexact flag */
77                         if (huge + x > 0.0) {
78                                 u.bits.manh &= ~m;
79                                 u.bits.manl = 0;
80                         }
81                 }
82         } else if (e < LDBL_MANT_DIG - 1) {
83                 uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
84                 if ((u.bits.manl & m) == 0)
85                         return x;  /* x is integral */
86                 if (u.bits.sign) {
87                         if (e == MANH_SIZE - 1)
88                                 INC_MANH(u, 1);
89                         else {
90                                 uint64_t o = u.bits.manl;
91                                 u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1);
92                                 if (u.bits.manl < o)   /* got a carry */
93                                         INC_MANH(u, 1);
94                         }
95                 }
96                 /* raise inexact flag */
97                 if (huge + x > 0.0)
98                         u.bits.manl &= ~m;
99         }
100         return u.e;
101 }
102 #endif