1 /* Round argument to nearest integral value according to current rounding
2    direction.
3    Copyright (C) 1997-2022 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    <https://www.gnu.org/licenses/>.  */
19 
20 #include <fenv.h>
21 #include <limits.h>
22 #include <math.h>
23 
24 #include <math-narrow-eval.h>
25 #include <math_private.h>
26 #include <libm-alias-float.h>
27 #include <fix-fp-int-convert-overflow.h>
28 
29 static const float two23[2] =
30 {
31   8.3886080000e+06, /* 0x4B000000 */
32  -8.3886080000e+06, /* 0xCB000000 */
33 };
34 
35 
36 long int
__lrintf(float x)37 __lrintf (float x)
38 {
39   int32_t j0;
40   uint32_t i0;
41   float w;
42   float t;
43   long int result;
44   int sx;
45 
46   GET_FLOAT_WORD (i0, x);
47 
48   sx = i0 >> 31;
49   j0 = ((i0 >> 23) & 0xff) - 0x7f;
50   i0 &= 0x7fffff;
51   i0 |= 0x800000;
52 
53   if (j0 < (int32_t) (sizeof (long int) * 8) - 1)
54     {
55       if (j0 >= 23)
56 	result = (long int) i0 << (j0 - 23);
57       else
58 	{
59 	  w = math_narrow_eval (two23[sx] + x);
60 	  t = w - two23[sx];
61 	  GET_FLOAT_WORD (i0, t);
62 	  j0 = ((i0 >> 23) & 0xff) - 0x7f;
63 	  i0 &= 0x7fffff;
64 	  i0 |= 0x800000;
65 
66 	  result = (j0 < 0 ? 0 : i0 >> (23 - j0));
67 	}
68     }
69   else
70     {
71 #ifdef FE_INVALID
72       /* The number is too large.  Unless it rounds to LONG_MIN,
73 	 FE_INVALID must be raised and the return value is
74 	 unspecified.  */
75       if (FIX_FLT_LONG_CONVERT_OVERFLOW && x != (float) LONG_MIN)
76 	{
77 	  feraiseexcept (FE_INVALID);
78 	  return sx == 0 ? LONG_MAX : LONG_MIN;
79 	}
80 #endif
81       return (long int) x;
82     }
83 
84   return sx ? -result : result;
85 }
86 
87 libm_alias_float (__lrint, lrint)
88