1  /* s_floorl.c -- long double version of s_floor.c.
       2   */
       3  
       4  /*
       5   * ====================================================
       6   * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
       7   *
       8   * Developed at SunPro, a Sun Microsystems, Inc. business.
       9   * Permission to use, copy, modify, and distribute this
      10   * software is freely granted, provided that this notice
      11   * is preserved.
      12   * ====================================================
      13   */
      14  
      15  #if defined(LIBM_SCCS) && !defined(lint)
      16  static char rcsid[] = "$NetBSD: $";
      17  #endif
      18  
      19  /*
      20   * floorl(x)
      21   * Return x rounded toward -inf to integral value
      22   * Method:
      23   *	Bit twiddling.
      24   */
      25  
      26  #define NO_MATH_REDIRECT
      27  #include <math.h>
      28  #include <math_private.h>
      29  #include <libm-alias-ldouble.h>
      30  #include <math-use-builtins.h>
      31  
      32  _Float128
      33  __floorl (_Float128 x)
      34  {
      35  #if USE_FLOORL_BUILTIN
      36    return __builtin_floorl (x);
      37  #else
      38    /* Use generic implementation.  */
      39    int64_t i0, i1, j0;
      40    uint64_t i, j;
      41    GET_LDOUBLE_WORDS64 (i0, i1, x);
      42    j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
      43    if (j0 < 48)
      44      {
      45        if (j0 < 0)
      46  	{
      47  	  /* return 0 * sign (x) if |x| < 1 */
      48  	  if (i0 >= 0)
      49  	    {
      50  	      i0 = i1 = 0;
      51  	    }
      52  	  else if (((i0 & 0x7fffffffffffffffLL) | i1) != 0)
      53  	    {
      54  	      i0 = 0xbfff000000000000ULL;
      55  	      i1 = 0;
      56  	    }
      57  	}
      58        else
      59  	{
      60  	  i = (0x0000ffffffffffffULL) >> j0;
      61  	  if (((i0 & i) | i1) == 0)
      62  	    return x;		/* x is integral  */
      63  	  if (i0 < 0)
      64  	    i0 += (0x0001000000000000LL) >> j0;
      65  	  i0 &= (~i);
      66  	  i1 = 0;
      67  	}
      68      }
      69    else if (j0 > 111)
      70      {
      71        if (j0 == 0x4000)
      72  	return x + x;		/* inf or NaN  */
      73        else
      74  	return x;		/* x is integral  */
      75      }
      76    else
      77      {
      78        i = -1ULL >> (j0 - 48);
      79        if ((i1 & i) == 0)
      80  	return x;		/* x is integral  */
      81        if (i0 < 0)
      82  	{
      83  	  if (j0 == 48)
      84  	    i0 += 1;
      85  	  else
      86  	    {
      87  	      j = i1 + (1LL << (112 - j0));
      88  	      if (j < i1)
      89  		i0 += 1 ;	/* got a carry */
      90  	      i1 = j;
      91  	    }
      92  	}
      93        i1 &= (~i);
      94      }
      95    SET_LDOUBLE_WORDS64 (x, i0, i1);
      96    return x;
      97  #endif /* ! USE_FLOORL_BUILTIN  */
      98  }
      99  libm_alias_ldouble (__floor, floor)