1 /* Round double value to long long int.
2    Copyright (C) 1997-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #define lround __hidden_lround
20 #define __lround __hidden___lround
21 
22 #include <fenv.h>
23 #include <limits.h>
24 #include <math.h>
25 #include <sysdep.h>
26 
27 #include <math_private.h>
28 #include <libm-alias-double.h>
29 #include <fix-fp-int-convert-overflow.h>
30 
31 long long int
__llround(double x)32 __llround (double x)
33 {
34   int32_t j0;
35   int64_t i0;
36   long long int result;
37   int sign;
38 
39   EXTRACT_WORDS64 (i0, x);
40   j0 = ((i0 >> 52) & 0x7ff) - 0x3ff;
41   sign = i0 < 0 ? -1 : 1;
42   i0 &= UINT64_C(0xfffffffffffff);
43   i0 |= UINT64_C(0x10000000000000);
44 
45   if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
46     {
47       if (j0 < 0)
48 	return j0 < -1 ? 0 : sign;
49       else if (j0 >= 52)
50 	result = i0 << (j0 - 52);
51       else
52 	{
53 	  i0 += UINT64_C(0x8000000000000) >> j0;
54 
55 	  result = i0 >> (52 - j0);
56 	}
57     }
58   else
59     {
60 #ifdef FE_INVALID
61       /* The number is too large.  Unless it rounds to LLONG_MIN,
62 	 FE_INVALID must be raised and the return value is
63 	 unspecified.  */
64       if (FIX_DBL_LLONG_CONVERT_OVERFLOW && x != (double) LLONG_MIN)
65 	{
66 	  feraiseexcept (FE_INVALID);
67 	  return sign == 1 ? LLONG_MAX : LLONG_MIN;
68 	}
69 #endif
70       return (long long int) x;
71     }
72 
73   return sign * result;
74 }
75 
76 libm_alias_double (__llround, llround)
77 
78 /* long has the same width as long long on LP64 machines, so use an alias.  */
79 #undef lround
80 #undef __lround
81 #ifdef _LP64
82 strong_alias (__llround, __lround)
83 libm_alias_double (__lround, lround)
84 #endif
85