Update copyright notices with scripts/update-copyrights
[jlayton/glibc.git] / sysdeps / ieee754 / ldbl-128ibm / s_lroundl.c
1 /* Round to long int long double floating-point values.
2    IBM extended format long double version.
3    Copyright (C) 2006-2014 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, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <math.h>
21 #include <fenv_libc.h>
22 #include <math_ldbl_opt.h>
23 #include <float.h>
24 #include <ieee754.h>
25
26 long
27 __lroundl (long double x)
28 {
29   double xh, xl;
30   long res, hi, lo;
31
32   ldbl_unpack (x, &xh, &xl);
33
34   /* Limit the range of values handled by the conversion to long.
35      We do this because we aren't sure whether that conversion properly
36      raises FE_INVALID.  */
37   if (
38 #if __LONG_MAX__ == 2147483647
39       __builtin_expect
40       ((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1)
41 #else
42       __builtin_expect
43       ((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1)
44 #endif
45 #if !defined (FE_INVALID)
46       || 1
47 #endif
48     )
49     {
50 #if __LONG_MAX__ == 2147483647
51       long long llhi = (long long) xh;
52       if (llhi != (long) llhi)
53         hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__;
54       else
55         hi = llhi;
56       xh -= hi;
57 #else
58       if (__builtin_expect ((xh == -(double) (-__LONG_MAX__ - 1)), 0))
59         {
60           /* When XH is 9223372036854775808.0, converting to long long will
61              overflow, resulting in an invalid operation.  However, XL might
62              be negative and of sufficient magnitude that the overall long
63              double is in fact in range.  Avoid raising an exception.  In any
64              case we need to convert this value specially, because
65              the converted value is not exactly represented as a double
66              thus subtracting HI from XH suffers rounding error.  */
67           hi = __LONG_MAX__;
68           xh = 1.0;
69         }
70       else
71         {
72           hi = (long) xh;
73           xh -= hi;
74         }
75 #endif
76       ldbl_canonicalize (&xh, &xl);
77
78       lo = (long) xh;
79
80       /* Peg at max/min values, assuming that the above conversions do so.
81          Strictly speaking, we can return anything for values that overflow,
82          but this is more useful.  */
83       res = hi + lo;
84
85       /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
86       if (__builtin_expect (((~(hi ^ lo) & (res ^ hi)) < 0), 0))
87         goto overflow;
88
89       xh -= lo;
90       ldbl_canonicalize (&xh, &xl);
91
92       hi = res;
93       if (xh > 0.5)
94         {
95           res += 1;
96         }
97       else if (xh == 0.5)
98         {
99           if (xl > 0.0 || (xl == 0.0 && res >= 0))
100             res += 1;
101         }
102       else if (-xh > 0.5)
103         {
104           res -= 1;
105         }
106       else if (-xh == 0.5)
107         {
108           if (xl < 0.0 || (xl == 0.0 && res <= 0))
109             res -= 1;
110         }
111
112       if (__builtin_expect (((~(hi ^ (res - hi)) & (res ^ hi)) < 0), 0))
113         goto overflow;
114
115       return res;
116     }
117   else
118     {
119       if (xh > 0.0)
120         hi = __LONG_MAX__;
121       else if (xh < 0.0)
122         hi = -__LONG_MAX__ - 1;
123       else
124         /* Nan */
125         hi = 0;
126     }
127
128 overflow:
129 #ifdef FE_INVALID
130   feraiseexcept (FE_INVALID);
131 #endif
132   return hi;
133 }
134
135 long_double_symbol (libm, __lroundl, lroundl);