Back to index

glibc  2.9
s_floorl.c
Go to the documentation of this file.
00001 /* s_floorl.c -- long double version of s_floor.c.
00002  * Conversion to long double by Ulrich Drepper,
00003  * Cygnus Support, drepper@cygnus.com.
00004  */
00005 
00006 /*
00007  * ====================================================
00008  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00009  *
00010  * Developed at SunPro, a Sun Microsystems, Inc. business.
00011  * Permission to use, copy, modify, and distribute this
00012  * software is freely granted, provided that this notice
00013  * is preserved.
00014  * ====================================================
00015  */
00016 
00017 #if defined(LIBM_SCCS) && !defined(lint)
00018 static char rcsid[] = "$NetBSD: $";
00019 #endif
00020 
00021 /*
00022  * floorl(x)
00023  * Return x rounded toward -inf to integral value
00024  * Method:
00025  *     Bit twiddling.
00026  * Exception:
00027  *     Inexact flag raised if x not equal to floor(x).
00028  */
00029 
00030 #include "math.h"
00031 #include "math_private.h"
00032 
00033 #ifdef __STDC__
00034 static const long double huge = 1.0e4930;
00035 #else
00036 static long double huge = 1.0e4930;
00037 #endif
00038 
00039 #ifdef __STDC__
00040        long double __floorl(long double x)
00041 #else
00042        long double __floorl(x)
00043        long double x;
00044 #endif
00045 {
00046        int32_t i1,j0;
00047        u_int32_t i,j,se,i0,sx;
00048        GET_LDOUBLE_WORDS(se,i0,i1,x);
00049        sx = (se>>15)&1;
00050        j0 = (se&0x7fff)-0x3fff;
00051        if(j0<31) {
00052            if(j0<0) {       /* raise inexact if x != 0 */
00053               if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
00054                   if(sx==0) {se=0;i0=i1=0;}
00055                   else if(((se&0x7fff)|i0|i1)!=0)
00056                      { se=0xbfff;i0=i1=0;}
00057               }
00058            } else {
00059               i = (0x7fffffff)>>j0;
00060               if(((i0&i)|i1)==0) return x; /* x is integral */
00061               if(huge+x>0.0) {     /* raise inexact flag */
00062                   if(sx) {
00063                      if (j0>0 && (i0+(0x80000000>>j0))>i0)
00064                        i0 += (0x80000000)>>j0;
00065                      else
00066                        {
00067                          i = 0x7fffffff;
00068                          ++se;
00069                        }
00070                   }
00071                   i0 &= (~i); i1=0;
00072               }
00073            }
00074        } else if (j0>62) {
00075            if(j0==0x4000) return x+x;     /* inf or NaN */
00076            else return x;          /* x is integral */
00077        } else {
00078            i = ((u_int32_t)(0xffffffff))>>(j0-31);
00079            if((i1&i)==0) return x; /* x is integral */
00080            if(huge+x>0.0) {               /* raise inexact flag */
00081               if(sx) {
00082                   if(j0==31) i0+=1;
00083                   else {
00084                      j = i1+(1<<(63-j0));
00085                      if(j<i1) i0 +=1 ;    /* got a carry */
00086                      i1=j;
00087                   }
00088               }
00089               i1 &= (~i);
00090            }
00091        }
00092        SET_LDOUBLE_WORDS(x,se,i0,i1);
00093        return x;
00094 }
00095 weak_alias (__floorl, floorl)