Back to index

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