(root)/
glibc-2.38/
sysdeps/
ieee754/
ldbl-128ibm/
s_llrintl.c
       1  /* Round to long long int long double floating-point values.
       2     IBM extended format long double version.
       3     Copyright (C) 2006-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 <math.h>
      21  #include <fenv.h>
      22  #include <math_private.h>
      23  #include <math_ldbl_opt.h>
      24  #include <float.h>
      25  #include <ieee754.h>
      26  
      27  
      28  long long
      29  __llrintl (long double x)
      30  {
      31    double xh, xl;
      32    long long res, hi, lo;
      33    int save_round;
      34  
      35    ldbl_unpack (x, &xh, &xl);
      36  
      37    /* Limit the range of values handled by the conversion to long long.
      38       We do this because we aren't sure whether that conversion properly
      39       raises FE_INVALID.  */
      40    if (__builtin_expect
      41        ((__builtin_fabs (xh) <= -(double) (-__LONG_LONG_MAX__ - 1)), 1)
      42  #if !defined (FE_INVALID)
      43        || 1
      44  #endif
      45      )
      46      {
      47        save_round = fegetround ();
      48  
      49        if (__glibc_unlikely ((xh == -(double) (-__LONG_LONG_MAX__ - 1))))
      50  	{
      51  	  /* When XH is 9223372036854775808.0, converting to long long will
      52  	     overflow, resulting in an invalid operation.  However, XL might
      53  	     be negative and of sufficient magnitude that the overall long
      54  	     double is in fact in range.  Avoid raising an exception.  In any
      55  	     case we need to convert this value specially, because
      56  	     the converted value is not exactly represented as a double
      57  	     thus subtracting HI from XH suffers rounding error.  */
      58  	  hi = __LONG_LONG_MAX__;
      59  	  xh = 1.0;
      60  	}
      61        else
      62  	{
      63  	  hi = (long long) xh;
      64  	  xh -= hi;
      65  	}
      66        ldbl_canonicalize (&xh, &xl);
      67  
      68        lo = (long long) xh;
      69  
      70        /* Peg at max/min values, assuming that the above conversions do so.
      71           Strictly speaking, we can return anything for values that overflow,
      72           but this is more useful.  */
      73        res = hi + lo;
      74  
      75        /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
      76        if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0)))
      77  	goto overflow;
      78  
      79        xh -= lo;
      80        ldbl_canonicalize (&xh, &xl);
      81  
      82        hi = res;
      83        switch (save_round)
      84  	{
      85  	case FE_TONEAREST:
      86  	  if (fabs (xh) < 0.5
      87  	      || (fabs (xh) == 0.5
      88  		  && ((xh > 0.0 && xl < 0.0)
      89  		      || (xh < 0.0 && xl > 0.0)
      90  		      || (xl == 0.0 && (res & 1) == 0))))
      91  	    return res;
      92  
      93  	  if (xh < 0.0)
      94  	    res -= 1;
      95  	  else
      96  	    res += 1;
      97  	  break;
      98  
      99  	case FE_TOWARDZERO:
     100  	  if (res > 0 && (xh < 0.0 || (xh == 0.0 && xl < 0.0)))
     101  	    res -= 1;
     102  	  else if (res < 0 && (xh > 0.0 || (xh == 0.0 && xl > 0.0)))
     103  	    res += 1;
     104  	  return res;
     105  	  break;
     106  
     107  	case FE_UPWARD:
     108  	  if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
     109  	    res += 1;
     110  	  break;
     111  
     112  	case FE_DOWNWARD:
     113  	  if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
     114  	    res -= 1;
     115  	  break;
     116  	}
     117  
     118        if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0)))
     119  	goto overflow;
     120  
     121        return res;
     122      }
     123    else
     124      {
     125        if (xh > 0.0)
     126  	hi = __LONG_LONG_MAX__;
     127        else if (xh < 0.0)
     128  	hi = -__LONG_LONG_MAX__ - 1;
     129        else
     130  	/* Nan */
     131  	hi = 0;
     132      }
     133  
     134  overflow:
     135  #ifdef FE_INVALID
     136    feraiseexcept (FE_INVALID);
     137  #endif
     138    return hi;
     139  }
     140  
     141  long_double_symbol (libm, __llrintl, llrintl);