Back to index

glibc  2.9
s_lrintl.c
Go to the documentation of this file.
00001 /* Round to long int long double floating-point values.
00002    IBM extended format long double version.
00003    Copyright (C) 2006 Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <math.h>
00022 #include <fenv_libc.h>
00023 #include <math_ldbl_opt.h>
00024 #include <float.h>
00025 #include <ieee754.h>
00026 
00027 
00028 #ifdef __STDC__
00029 long
00030 __lrintl (long double x)
00031 #else
00032 long
00033 __lrintl (x)
00034      long double x;
00035 #endif
00036 {
00037   double xh, xl;
00038   long res, hi, lo;
00039   int save_round;
00040 
00041   ldbl_unpack (x, &xh, &xl);
00042 
00043   /* Limit the range of values handled by the conversion to long.
00044      We do this because we aren't sure whether that conversion properly
00045      raises FE_INVALID.  */
00046   if (
00047 #if __LONG_MAX__ == 2147483647
00048       __builtin_expect
00049       ((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1)
00050 #else
00051       __builtin_expect
00052       ((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1)
00053 #endif
00054 #if !defined (FE_INVALID)
00055       || 1
00056 #endif
00057     )
00058     {
00059       save_round = fegetround ();
00060 
00061 #if __LONG_MAX__ == 2147483647
00062       long long llhi = (long long) xh;
00063       if (llhi != (long) llhi)
00064        hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__;
00065       else
00066        hi = llhi;
00067       xh -= hi;
00068 #else
00069       if (__builtin_expect ((xh == -(double) (-__LONG_MAX__ - 1)), 0))
00070        {
00071          /* When XH is 9223372036854775808.0, converting to long long will
00072             overflow, resulting in an invalid operation.  However, XL might
00073             be negative and of sufficient magnitude that the overall long
00074             double is in fact in range.  Avoid raising an exception.  In any
00075             case we need to convert this value specially, because
00076             the converted value is not exactly represented as a double
00077             thus subtracting HI from XH suffers rounding error.  */
00078          hi = __LONG_MAX__;
00079          xh = 1.0;
00080        }
00081       else
00082        {
00083          hi = (long) xh;
00084          xh -= hi;
00085        }
00086 #endif
00087       ldbl_canonicalize (&xh, &xl);
00088 
00089       lo = (long) xh;
00090 
00091       /* Peg at max/min values, assuming that the above conversions do so.
00092          Strictly speaking, we can return anything for values that overflow,
00093          but this is more useful.  */
00094       res = hi + lo;
00095 
00096       /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
00097       if (__builtin_expect (((~(hi ^ lo) & (res ^ hi)) < 0), 0))
00098        goto overflow;
00099 
00100       xh -= lo;
00101       ldbl_canonicalize (&xh, &xl);
00102 
00103       hi = res;
00104       switch (save_round)
00105        {
00106        case FE_TONEAREST:
00107          if (fabs (xh) < 0.5
00108              || (fabs (xh) == 0.5
00109                 && ((xh > 0.0 && xl < 0.0)
00110                     || (xh < 0.0 && xl > 0.0)
00111                     || (xl == 0.0 && (res & 1) == 0))))
00112            return res;
00113 
00114          if (xh < 0.0)
00115            res -= 1;
00116          else
00117            res += 1;
00118          break;
00119 
00120        case FE_TOWARDZERO:
00121          if (res > 0 && (xh < 0.0 || (xh == 0.0 && xl < 0.0)))
00122            res -= 1;
00123          else if (res < 0 && (xh > 0.0 || (xh == 0.0 && xl > 0.0)))
00124            res += 1;
00125          return res;
00126          break;
00127 
00128        case FE_UPWARD:
00129          if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
00130            res += 1;
00131          break;
00132 
00133        case FE_DOWNWARD:
00134          if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
00135            res -= 1;
00136          break;
00137        }
00138 
00139       if (__builtin_expect (((~(hi ^ (res - hi)) & (res ^ hi)) < 0), 0))
00140        goto overflow;
00141 
00142       return res;
00143     }
00144   else
00145     {
00146       if (xh > 0.0)
00147        hi = __LONG_MAX__;
00148       else if (xh < 0.0)
00149        hi = -__LONG_MAX__ - 1;
00150       else
00151        /* Nan */
00152        hi = 0;
00153     }
00154 
00155 overflow:
00156 #ifdef FE_INVALID
00157   feraiseexcept (FE_INVALID);
00158 #endif
00159   return hi;
00160 }
00161 
00162 long_double_symbol (libm, __lrintl, lrintl);