Back to index

glibc  2.9
s_lroundl.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 #ifdef __STDC__
00028 long
00029 __lroundl (long double x)
00030 #else
00031 long
00032 __lroundl (x)
00033      long double x;
00034 #endif
00035 {
00036   double xh, xl;
00037   long res, hi, lo;
00038 
00039   ldbl_unpack (x, &xh, &xl);
00040 
00041   /* Limit the range of values handled by the conversion to long.
00042      We do this because we aren't sure whether that conversion properly
00043      raises FE_INVALID.  */
00044   if (
00045 #if __LONG_MAX__ == 2147483647
00046       __builtin_expect
00047       ((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1)
00048 #else
00049       __builtin_expect
00050       ((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1)
00051 #endif
00052 #if !defined (FE_INVALID)
00053       || 1
00054 #endif
00055     )
00056     {
00057 #if __LONG_MAX__ == 2147483647
00058       long long llhi = (long long) xh;
00059       if (llhi != (long) llhi)
00060        hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__;
00061       else
00062        hi = llhi;
00063       xh -= hi;
00064 #else
00065       if (__builtin_expect ((xh == -(double) (-__LONG_MAX__ - 1)), 0))
00066        {
00067          /* When XH is 9223372036854775808.0, converting to long long will
00068             overflow, resulting in an invalid operation.  However, XL might
00069             be negative and of sufficient magnitude that the overall long
00070             double is in fact in range.  Avoid raising an exception.  In any
00071             case we need to convert this value specially, because
00072             the converted value is not exactly represented as a double
00073             thus subtracting HI from XH suffers rounding error.  */
00074          hi = __LONG_MAX__;
00075          xh = 1.0;
00076        }
00077       else
00078        {
00079          hi = (long) xh;
00080          xh -= hi;
00081        }
00082 #endif
00083       ldbl_canonicalize (&xh, &xl);
00084 
00085       lo = (long) xh;
00086 
00087       /* Peg at max/min values, assuming that the above conversions do so.
00088          Strictly speaking, we can return anything for values that overflow,
00089          but this is more useful.  */
00090       res = hi + lo;
00091 
00092       /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
00093       if (__builtin_expect (((~(hi ^ lo) & (res ^ hi)) < 0), 0))
00094        goto overflow;
00095 
00096       xh -= lo;
00097       ldbl_canonicalize (&xh, &xl);
00098 
00099       hi = res;
00100       if (xh > 0.5)
00101        {
00102          res += 1;
00103        }
00104       else if (xh == 0.5)
00105        {
00106          if (xl > 0.0 || (xl == 0.0 && res >= 0))
00107            res += 1;
00108        }
00109       else if (-xh > 0.5)
00110        {
00111          res -= 1;
00112        }
00113       else if (-xh == 0.5)
00114        {
00115          if (xl < 0.0 || (xl == 0.0 && res <= 0))
00116            res -= 1;
00117        }
00118 
00119       if (__builtin_expect (((~(hi ^ (res - hi)) & (res ^ hi)) < 0), 0))
00120        goto overflow;
00121 
00122       return res;
00123     }
00124   else
00125     {
00126       if (xh > 0.0)
00127        hi = __LONG_MAX__;
00128       else if (xh < 0.0)
00129        hi = -__LONG_MAX__ - 1;
00130       else
00131        /* Nan */
00132        hi = 0;
00133     }
00134 
00135 overflow:
00136 #ifdef FE_INVALID
00137   feraiseexcept (FE_INVALID);
00138 #endif
00139   return hi;
00140 }
00141 
00142 long_double_symbol (libm, __lroundl, lroundl);