chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / ieee754 / ldbl-128ibm / s_lrintl.c
1 /* Round to long int long double floating-point values.
2    IBM extended format long double version.
3    Copyright (C) 2006 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <math.h>
22 #include <fenv_libc.h>
23 #include <math_ldbl_opt.h>
24 #include <float.h>
25 #include <ieee754.h>
26
27
28 #ifdef __STDC__
29 long
30 __lrintl (long double x)
31 #else
32 long
33 __lrintl (x)
34      long double x;
35 #endif
36 {
37   double xh, xl;
38   long res, hi, lo;
39   int save_round;
40
41   ldbl_unpack (x, &xh, &xl);
42
43   /* Limit the range of values handled by the conversion to long.
44      We do this because we aren't sure whether that conversion properly
45      raises FE_INVALID.  */
46   if (
47 #if __LONG_MAX__ == 2147483647
48       __builtin_expect
49       ((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1)
50 #else
51       __builtin_expect
52       ((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1)
53 #endif
54 #if !defined (FE_INVALID)
55       || 1
56 #endif
57     )
58     {
59       save_round = fegetround ();
60
61 #if __LONG_MAX__ == 2147483647
62       long long llhi = (long long) xh;
63       if (llhi != (long) llhi)
64         hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__;
65       else
66         hi = llhi;
67       xh -= hi;
68 #else
69       if (__builtin_expect ((xh == -(double) (-__LONG_MAX__ - 1)), 0))
70         {
71           /* When XH is 9223372036854775808.0, converting to long long will
72              overflow, resulting in an invalid operation.  However, XL might
73              be negative and of sufficient magnitude that the overall long
74              double is in fact in range.  Avoid raising an exception.  In any
75              case we need to convert this value specially, because
76              the converted value is not exactly represented as a double
77              thus subtracting HI from XH suffers rounding error.  */
78           hi = __LONG_MAX__;
79           xh = 1.0;
80         }
81       else
82         {
83           hi = (long) xh;
84           xh -= hi;
85         }
86 #endif
87       ldbl_canonicalize (&xh, &xl);
88
89       lo = (long) xh;
90
91       /* Peg at max/min values, assuming that the above conversions do so.
92          Strictly speaking, we can return anything for values that overflow,
93          but this is more useful.  */
94       res = hi + lo;
95
96       /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
97       if (__builtin_expect (((~(hi ^ lo) & (res ^ hi)) < 0), 0))
98         goto overflow;
99
100       xh -= lo;
101       ldbl_canonicalize (&xh, &xl);
102
103       hi = res;
104       switch (save_round)
105         {
106         case FE_TONEAREST:
107           if (fabs (xh) < 0.5
108               || (fabs (xh) == 0.5
109                   && ((xh > 0.0 && xl < 0.0)
110                       || (xh < 0.0 && xl > 0.0)
111                       || (xl == 0.0 && (res & 1) == 0))))
112             return res;
113
114           if (xh < 0.0)
115             res -= 1;
116           else
117             res += 1;
118           break;
119
120         case FE_TOWARDZERO:
121           if (res > 0 && (xh < 0.0 || (xh == 0.0 && xl < 0.0)))
122             res -= 1;
123           else if (res < 0 && (xh > 0.0 || (xh == 0.0 && xl > 0.0)))
124             res += 1;
125           return res;
126           break;
127
128         case FE_UPWARD:
129           if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
130             res += 1;
131           break;
132
133         case FE_DOWNWARD:
134           if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
135             res -= 1;
136           break;
137         }
138
139       if (__builtin_expect (((~(hi ^ (res - hi)) & (res ^ hi)) < 0), 0))
140         goto overflow;
141
142       return res;
143     }
144   else
145     {
146       if (xh > 0.0)
147         hi = __LONG_MAX__;
148       else if (xh < 0.0)
149         hi = -__LONG_MAX__ - 1;
150       else
151         /* Nan */
152         hi = 0;
153     }
154
155 overflow:
156 #ifdef FE_INVALID
157   feraiseexcept (FE_INVALID);
158 #endif
159   return hi;
160 }
161
162 long_double_symbol (libm, __lrintl, lrintl);