1 /* Round long 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 #include <fenv.h>
20 #include <limits.h>
21 #include <math.h>
22 
23 #include <math_private.h>
24 #include <libm-alias-ldouble.h>
25 
26 
27 long long int
__llroundl(long double x)28 __llroundl (long double x)
29 {
30   int32_t j0;
31   uint32_t se, i1, i0;
32   long long int result;
33   int sign;
34 
35   GET_LDOUBLE_WORDS (se, i0, i1, x);
36   j0 = (se & 0x7fff) - 0x3fff;
37   sign = (se & 0x8000) != 0 ? -1 : 1;
38 
39   if (j0 < 31)
40     {
41       if (j0 < 0)
42 	return j0 < -1 ? 0 : sign;
43       else
44 	{
45 	  uint32_t j = i0 + (0x40000000 >> j0);
46 	  if (j < i0)
47 	    {
48 	      j >>= 1;
49 	      j |= 0x80000000;
50 	      ++j0;
51 	    }
52 
53 	  result = j >> (31 - j0);
54 	}
55     }
56   else if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
57     {
58       if (j0 >= 63)
59 	result = (((long long int) i0 << 32) | i1) << (j0 - 63);
60       else
61 	{
62 	  uint32_t j = i1 + (0x80000000 >> (j0 - 31));
63 
64 	  result = (long long int) i0;
65 	  if (j < i1)
66 	    ++result;
67 
68 	  if (j0 > 31)
69 	    {
70 	      result = (result << (j0 - 31)) | (j >> (63 - j0));
71 #ifdef FE_INVALID
72 	      if (sign == 1 && result == LLONG_MIN)
73 		/* Rounding brought the value out of range.  */
74 		feraiseexcept (FE_INVALID);
75 #endif
76 	    }
77 	}
78     }
79   else
80     {
81       /* The number is too large.  It is left implementation defined
82 	 what happens.  */
83       return (long long int) x;
84     }
85 
86   return sign * result;
87 }
88 
89 libm_alias_ldouble (__llround, llround)
90