]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / ieee754 / ldbl-128ibm / s_nearbyintl.c
CommitLineData
f964490f
RM
1/* Round to int long double floating-point values without raising inexact.
2 IBM extended format long double version.
b168057a 3 Copyright (C) 2006-2015 Free Software Foundation, Inc.
f964490f
RM
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
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
f964490f
RM
19
20/* This has been coded in assembler because GCC makes such a mess of it
21 when it's coded in C. */
22
23#include <math.h>
3e694268 24#include <math_private.h>
f964490f
RM
25#include <fenv.h>
26#include <math_ldbl_opt.h>
27#include <float.h>
28#include <ieee754.h>
29
30
f964490f
RM
31long double
32__nearbyintl (long double x)
f964490f
RM
33{
34 fenv_t env;
35 static const long double TWO52 = 4503599627370496.0L;
36 union ibm_extended_long_double u;
9605ca6c 37 u.ld = x;
f964490f 38
9605ca6c 39 if (fabs (u.d[0].d) < TWO52)
f964490f 40 {
754c5a08 41 double xh = u.d[0].d;
9605ca6c 42 double high = u.d[0].d;
f964490f
RM
43 feholdexcept (&env);
44 if (high > 0.0)
45 {
46 high += TWO52;
47 high -= TWO52;
48 if (high == -0.0) high = 0.0;
49 }
50 else if (high < 0.0)
51 {
52 high -= TWO52;
53 high += TWO52;
54 if (high == 0.0) high = -0.0;
55 }
754c5a08
RS
56 if (u.d[1].d > 0.0 && (xh - high == 0.5))
57 high += 1.0;
58 else if (u.d[1].d < 0.0 && (-(xh - high) == 0.5))
59 high -= 1.0;
9605ca6c
AM
60 u.d[0].d = high;
61 u.d[1].d = 0.0;
62 math_force_eval (u.d[0]);
63 math_force_eval (u.d[1]);
f964490f
RM
64 fesetenv (&env);
65 }
9605ca6c 66 else if (fabs (u.d[1].d) < TWO52 && u.d[1].d != 0.0)
f964490f
RM
67 {
68 double high, low, tau;
69 /* In this case we have to round the low double and handle any
70 adjustment to the high double that may be caused by rounding
71 (up). This is complicated by the fact that the high double
72 may already be rounded and the low double may have the
73 opposite sign to compensate. */
74 feholdexcept (&env);
9605ca6c 75 if (u.d[0].d > 0.0)
f964490f 76 {
9605ca6c 77 if (u.d[1].d > 0.0)
f964490f
RM
78 {
79 /* If the high/low doubles are the same sign then simply
80 round the low double. */
9605ca6c
AM
81 high = u.d[0].d;
82 low = u.d[1].d;
f964490f 83 }
9605ca6c 84 else if (u.d[1].d < 0.0)
f964490f
RM
85 {
86 /* Else the high double is pre rounded and we need to
87 adjust for that. */
3b6d574e 88
9605ca6c
AM
89 tau = __nextafter (u.d[0].d, 0.0);
90 tau = (u.d[0].d - tau) * 2.0;
91 high = u.d[0].d - tau;
92 low = u.d[1].d + tau;
f964490f
RM
93 }
94 low += TWO52;
95 low -= TWO52;
96 }
9605ca6c 97 else if (u.d[0].d < 0.0)
f964490f 98 {
9605ca6c 99 if (u.d[1].d < 0.0)
f964490f
RM
100 {
101 /* If the high/low doubles are the same sign then simply
102 round the low double. */
9605ca6c
AM
103 high = u.d[0].d;
104 low = u.d[1].d;
f964490f 105 }
9605ca6c 106 else if (u.d[1].d > 0.0)
f964490f
RM
107 {
108 /* Else the high double is pre rounded and we need to
109 adjust for that. */
9605ca6c
AM
110 tau = __nextafter (u.d[0].d, 0.0);
111 tau = (u.d[0].d - tau) * 2.0;
112 high = u.d[0].d - tau;
113 low = u.d[1].d + tau;
f964490f
RM
114 }
115 low = TWO52 - low;
116 low = -(low - TWO52);
117 }
9605ca6c
AM
118 u.d[0].d = high + low;
119 u.d[1].d = high - u.d[0].d + low;
120 math_force_eval (u.d[0]);
121 math_force_eval (u.d[1]);
f964490f
RM
122 fesetenv (&env);
123 }
124
9605ca6c 125 return u.ld;
f964490f
RM
126}
127
128long_double_symbol (libm, __nearbyintl, nearbyintl);