(root)/
glibc-2.38/
sysdeps/
ieee754/
dbl-64/
s_llrint.c
       1  /* Round argument to nearest integral value according to current rounding
       2     direction.
       3     Copyright (C) 1997-2023 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-double.h>
      27  #include <fix-fp-int-convert-overflow.h>
      28  #include <math-use-builtins.h>
      29  
      30  
      31  long long int
      32  __llrint (double x)
      33  {
      34  #if USE_LLRINT_BUILTIN
      35    return __builtin_llrint (x);
      36  #else
      37    /* Use generic implementation.  */
      38    static const double two52[2] =
      39    {
      40      4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
      41     -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
      42    };
      43  
      44    int32_t j0;
      45    uint32_t i1, i0;
      46    long long int result;
      47    double w;
      48    double t;
      49    int sx;
      50  
      51    EXTRACT_WORDS (i0, i1, x);
      52    j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
      53    sx = i0 >> 31;
      54    i0 &= 0xfffff;
      55    i0 |= 0x100000;
      56  
      57    if (j0 < 20)
      58      {
      59        w = math_narrow_eval (two52[sx] + x);
      60        t = w - two52[sx];
      61        EXTRACT_WORDS (i0, i1, t);
      62        j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
      63        i0 &= 0xfffff;
      64        i0 |= 0x100000;
      65  
      66        result = (j0 < 0 ? 0 : i0 >> (20 - j0));
      67      }
      68    else if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
      69      {
      70        if (j0 >= 52)
      71  	result = (((long long int) i0 << 32) | i1) << (j0 - 52);
      72        else
      73  	{
      74  	  w = math_narrow_eval (two52[sx] + x);
      75  	  t = w - two52[sx];
      76  	  EXTRACT_WORDS (i0, i1, t);
      77  	  j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
      78  	  i0 &= 0xfffff;
      79  	  i0 |= 0x100000;
      80  
      81  	  if (j0 == 20)
      82  	    result = (long long int) i0;
      83  	  else
      84  	    result = ((long long int) i0 << (j0 - 20)) | (i1 >> (52 - j0));
      85  	}
      86      }
      87    else
      88      {
      89  #ifdef FE_INVALID
      90        /* The number is too large.  Unless it rounds to LLONG_MIN,
      91  	 FE_INVALID must be raised and the return value is
      92  	 unspecified.  */
      93        if (FIX_DBL_LLONG_CONVERT_OVERFLOW && x != (double) LLONG_MIN)
      94  	{
      95  	  feraiseexcept (FE_INVALID);
      96  	  return sx == 0 ? LLONG_MAX : LLONG_MIN;
      97  	}
      98  #endif
      99        return (long long int) x;
     100      }
     101  
     102    return sx ? -result : result;
     103  #endif /* ! USE_LLRINT_BUILTIN  */
     104  }
     105  
     106  libm_alias_double (__llrint, llrint)