2.5-18.1
[jlayton/glibc.git] / sysdeps / ieee754 / ldbl-128ibm / s_floorl.c
1 /* Round to 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 double
30 __floorl (long double x)
31 #else
32 long double
33 __floorl (x)
34      long double x;
35 #endif
36 {
37   double xh, xl, hi, lo;
38
39   ldbl_unpack (x, &xh, &xl);
40
41   /* Return Inf, Nan, +/-0 unchanged.  */
42   if (__builtin_expect (xh != 0.0
43                         && __builtin_isless (__builtin_fabs (xh),
44                                              __builtin_inf ()), 1))
45     {
46       int save_round = fegetround ();
47
48       /* Long double arithmetic, including the canonicalisation below,
49          only works in round-to-nearest mode.  */
50       fesetround (FE_TONEAREST);
51
52       /* Convert the high double to integer.  */
53       hi = ldbl_nearbyint (xh);
54
55       /* Subtract integral high part from the value.  */
56       xh -= hi;
57       ldbl_canonicalize (&xh, &xl);
58
59       /* Now convert the low double, adjusted for any remainder from the
60          high double.  */
61       lo = ldbl_nearbyint (xh);
62
63       /* Adjust the result when the remainder is non-zero.  nearbyint
64          rounds values to the nearest integer, and values halfway
65          between integers to the nearest even integer.  floorl must
66          round towards -Inf.  */
67       xh -= lo;
68       ldbl_canonicalize (&xh, &xl);
69
70       if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
71         lo += -1.0;
72
73       /* Ensure the final value is canonical.  In certain cases,
74          rounding causes hi,lo calculated so far to be non-canonical.  */
75       xh = hi;
76       xl = lo;
77       ldbl_canonicalize (&xh, &xl);
78
79       fesetround (save_round);
80     }
81
82   return ldbl_pack (xh, xl);
83 }
84
85 long_double_symbol (libm, __floorl, floorl);