Back to index

glibc  2.9
Functions
s_rintl.c File Reference
#include <math.h>
#include <fenv_libc.h>
#include <math_ldbl_opt.h>
#include <float.h>
#include <ieee754.h>

Go to the source code of this file.

Functions

long double __rintl (long double x)
 long_double_symbol (libm, __rintl, rintl)

Function Documentation

long double __rintl ( long double  x)

Definition at line 36 of file s_rintl.c.

{
  double xh, xl, hi, lo;

  ldbl_unpack (x, &xh, &xl);

  /* Return Inf, Nan, +/-0 unchanged.  */
  if (__builtin_expect (xh != 0.0
                     && __builtin_isless (__builtin_fabs (xh),
                                        __builtin_inf ()), 1))
    {
      double orig_xh;
      int save_round = fegetround ();

      /* Long double arithmetic, including the canonicalisation below,
        only works in round-to-nearest mode.  */
      fesetround (FE_TONEAREST);

      /* Convert the high double to integer.  */
      orig_xh = xh;
      hi = ldbl_nearbyint (xh);

      /* Subtract integral high part from the value.  If the low double
        happens to be exactly 0.5 or -0.5, you might think that this
        subtraction could result in an incorrect conversion.  For
        instance, subtracting an odd number would cause this function
        to round in the wrong direction.  However, if we have a
        canonical long double with the low double 0.5 or -0.5, then the
        high double must be even.  */
      xh -= hi;
      ldbl_canonicalize (&xh, &xl);

      /* Now convert the low double, adjusted for any remainder from the
        high double.  */
      lo = ldbl_nearbyint (xh);

      xh -= lo;
      ldbl_canonicalize (&xh, &xl);

      switch (save_round)
       {
       case FE_TONEAREST:
         if (xl > 0.0 && xh == 0.5)
           lo += 1.0;
         else if (xl < 0.0 && -xh == 0.5)
           lo -= 1.0;
         break;

       case FE_TOWARDZERO:
         if (orig_xh < 0.0)
           goto do_up;
         /* Fall thru */

       case FE_DOWNWARD:
         if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
           lo -= 1.0;
         break;

       case FE_UPWARD:
       do_up:
         if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
           lo += 1.0;
         break;
       }

      /* Ensure the final value is canonical.  In certain cases,
         rounding causes hi,lo calculated so far to be non-canonical.  */
      xh = hi;
      xl = lo;
      ldbl_canonicalize (&xh, &xl);

      /* Ensure we return -0 rather than +0 when appropriate.  */
      if (orig_xh < 0.0)
       xh = -__builtin_fabs (xh);

      fesetround (save_round);
    }

  return ldbl_pack (xh, xl);
}

Here is the call graph for this function:

long_double_symbol ( libm  ,
__rintl  ,
rintl   
)