Esempio n. 1
0
long double
__truncl (long double x)
{
  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;

      /* Long double arithmetic, including the canonicalisation below,
	 only works in round-to-nearest mode.  */

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

      /* Subtract integral high part from the value.  */
      xh -= hi;
      ldbl_canonicalize (&xh, &xl);

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

      /* Adjust the result when the remainder is non-zero.  nearbyint
         rounds values to the nearest integer, and values halfway
         between integers to the nearest even integer.  floorl must
         round towards -Inf.  */
      xh -= lo;
      ldbl_canonicalize (&xh, &xl);

      if (orig_xh < 0.0)
	{
	  if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
	    lo += 1.0;
	}
      else
	{
	  if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
	    lo -= 1.0;
	}

      /* 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);
    }

  return ldbl_pack (xh, xl);
}
Esempio n. 2
0
long double
__roundl (long double x)
{
  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;

      /* Long double arithmetic, including the canonicalisation below,
	 only works in round-to-nearest mode.  */

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

      /* Subtract integral high part from the value.  */
      xh -= hi;
      ldbl_canonicalize (&xh, &xl);

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

      /* Adjust the result when the remainder is exactly 0.5.  nearbyint
	 rounds values halfway between integers to the nearest even
	 integer.  roundl must round away from zero.
	 Also correct cases where nearbyint returns an incorrect value
	 for LO.  */
      xh -= lo;
      ldbl_canonicalize (&xh, &xl);
      if (xh == 0.5)
	{
	  if (xl > 0.0 || (xl == 0.0 && orig_xh > 0.0))
	    lo += 1.0;
	}
      else if (-xh == 0.5)
	{
	  if (xl < 0.0 || (xl == 0.0 && orig_xh < 0.0))
	    lo -= 1.0;
	}

      /* 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);
    }

  return ldbl_pack (xh, xl);
}
Esempio n. 3
0
long long
__llrintl (long double x)
{
  double xh, xl;
  long long res, hi, lo;
  int save_round;

  ldbl_unpack (x, &xh, &xl);

  /* Limit the range of values handled by the conversion to long long.
     We do this because we aren't sure whether that conversion properly
     raises FE_INVALID.  */
  if (__builtin_expect
      ((__builtin_fabs (xh) <= -(double) (-__LONG_LONG_MAX__ - 1)), 1)
#if !defined (FE_INVALID)
      || 1
#endif
    )
    {
      save_round = fegetround ();

      if (__glibc_unlikely ((xh == -(double) (-__LONG_LONG_MAX__ - 1))))
	{
	  /* When XH is 9223372036854775808.0, converting to long long will
	     overflow, resulting in an invalid operation.  However, XL might
	     be negative and of sufficient magnitude that the overall long
	     double is in fact in range.  Avoid raising an exception.  In any
	     case we need to convert this value specially, because
	     the converted value is not exactly represented as a double
	     thus subtracting HI from XH suffers rounding error.  */
	  hi = __LONG_LONG_MAX__;
	  xh = 1.0;
	}
      else
	{
	  hi = (long long) xh;
	  xh -= hi;
	}
      ldbl_canonicalize (&xh, &xl);

      lo = (long long) xh;

      /* Peg at max/min values, assuming that the above conversions do so.
         Strictly speaking, we can return anything for values that overflow,
         but this is more useful.  */
      res = hi + lo;

      /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
      if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0)))
	goto overflow;

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

      hi = res;
      switch (save_round)
	{
	case FE_TONEAREST:
	  if (fabs (xh) < 0.5
	      || (fabs (xh) == 0.5
		  && ((xh > 0.0 && xl < 0.0)
		      || (xh < 0.0 && xl > 0.0)
		      || (xl == 0.0 && (res & 1) == 0))))
	    return res;

	  if (xh < 0.0)
	    res -= 1;
	  else
	    res += 1;
	  break;

	case FE_TOWARDZERO:
	  if (res > 0 && (xh < 0.0 || (xh == 0.0 && xl < 0.0)))
	    res -= 1;
	  else if (res < 0 && (xh > 0.0 || (xh == 0.0 && xl > 0.0)))
	    res += 1;
	  return res;
	  break;

	case FE_UPWARD:
	  if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
	    res += 1;
	  break;

	case FE_DOWNWARD:
	  if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
	    res -= 1;
	  break;
	}

      if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0)))
	goto overflow;

      return res;
    }
  else
    {
      if (xh > 0.0)
	hi = __LONG_LONG_MAX__;
      else if (xh < 0.0)
	hi = -__LONG_LONG_MAX__ - 1;
      else
	/* Nan */
	hi = 0;
    }

overflow:
#ifdef FE_INVALID
  feraiseexcept (FE_INVALID);
#endif
  return hi;
}
Esempio n. 4
0
long
__lroundl (long double x)
{
  double xh, xl;
  long res, hi, lo;

  ldbl_unpack (x, &xh, &xl);

  /* Limit the range of values handled by the conversion to long.
     We do this because we aren't sure whether that conversion properly
     raises FE_INVALID.  */
  if (
#if __LONG_MAX__ == 2147483647
      __builtin_expect
      ((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1)
#else
      __builtin_expect
      ((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1)
#endif
#if !defined (FE_INVALID)
      || 1
#endif
    )
    {
#if __LONG_MAX__ == 2147483647
      long long llhi = (long long) xh;
      if (llhi != (long) llhi)
	hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__;
      else
	hi = llhi;
      xh -= hi;
#else
      if (__glibc_unlikely ((xh == -(double) (-__LONG_MAX__ - 1))))
	{
	  /* When XH is 9223372036854775808.0, converting to long long will
	     overflow, resulting in an invalid operation.  However, XL might
	     be negative and of sufficient magnitude that the overall long
	     double is in fact in range.  Avoid raising an exception.  In any
	     case we need to convert this value specially, because
	     the converted value is not exactly represented as a double
	     thus subtracting HI from XH suffers rounding error.  */
	  hi = __LONG_MAX__;
	  xh = 1.0;
	}
      else
	{
	  hi = (long) xh;
	  xh -= hi;
	}
#endif
      ldbl_canonicalize (&xh, &xl);

      lo = (long) xh;

      /* Peg at max/min values, assuming that the above conversions do so.
         Strictly speaking, we can return anything for values that overflow,
         but this is more useful.  */
      res = hi + lo;

      /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
      if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0)))
	goto overflow;

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

      hi = res;
      if (xh > 0.5)
	{
	  res += 1;
	}
      else if (xh == 0.5)
	{
	  if (xl > 0.0 || (xl == 0.0 && res >= 0))
	    res += 1;
	}
      else if (-xh > 0.5)
	{
	  res -= 1;
	}
      else if (-xh == 0.5)
	{
	  if (xl < 0.0 || (xl == 0.0 && res <= 0))
	    res -= 1;
	}

      if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0)))
	goto overflow;

      return res;
    }
  else
    {
      if (xh > 0.0)
	hi = __LONG_MAX__;
      else if (xh < 0.0)
	hi = -__LONG_MAX__ - 1;
      else
	/* Nan */
	hi = 0;
    }

overflow:
#ifdef FE_INVALID
  feraiseexcept (FE_INVALID);
#endif
  return hi;
}
Esempio n. 5
0
long double
__rintl (long double x)
{
    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);
}