Back to index

glibc  2.9
s_nearbyintl.c
Go to the documentation of this file.
00001 /* s_rintl.c -- long double version of s_rint.c.
00002  * Conversion to long double by Ulrich Drepper,
00003  * Cygnus Support, drepper@cygnus.com.
00004  */
00005 /* Adapted for use as nearbyint by Ulrich Drepper <drepper@cygnus.com>.  */
00006 
00007 /*
00008  * ====================================================
00009  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00010  *
00011  * Developed at SunPro, a Sun Microsystems, Inc. business.
00012  * Permission to use, copy, modify, and distribute this
00013  * software is freely granted, provided that this notice
00014  * is preserved.
00015  * ====================================================
00016  */
00017 
00018 /*
00019  * rintl(x)
00020  * Return x rounded to integral value according to the prevailing
00021  * rounding mode.
00022  * Method:
00023  *     Using floating addition.
00024  * Exception:
00025  *     Inexact flag raised if x not equal to rintl(x).
00026  */
00027 
00028 #include <fenv.h>
00029 #include "math.h"
00030 #include "math_private.h"
00031 
00032 #ifdef __STDC__
00033 static const long double
00034 #else
00035 static long double
00036 #endif
00037 TWO63[2]={
00038   9.223372036854775808000000e+18, /* 0x403E, 0x00000000, 0x00000000 */
00039  -9.223372036854775808000000e+18  /* 0xC03E, 0x00000000, 0x00000000 */
00040 };
00041 
00042 #ifdef __STDC__
00043        long double __nearbyintl(long double x)
00044 #else
00045        long double __nearbyintl(x)
00046        long double x;
00047 #endif
00048 {
00049        fenv_t env;
00050        int32_t se,j0,sx;
00051        u_int32_t i,i0,i1;
00052        long double w,t;
00053        GET_LDOUBLE_WORDS(se,i0,i1,x);
00054        sx = (se>>15)&1;
00055        j0 = (se&0x7fff)-0x3fff;
00056        if(j0<31) {
00057            if(j0<0) {
00058               if(((se&0x7fff)|i0|i1)==0) return x;
00059               i1 |= i0;
00060               i0 &= 0xe0000000;
00061               i0 |= (i1|-i1)&0x80000000;
00062               SET_LDOUBLE_MSW(x,i0);
00063               feholdexcept (&env);
00064                w = TWO63[sx]+x;
00065                t = w-TWO63[sx];
00066               fesetenv (&env);
00067               GET_LDOUBLE_EXP(i0,t);
00068               SET_LDOUBLE_EXP(t,(i0&0x7fff)|(sx<<15));
00069                return t;
00070            } else {
00071               i = (0x7fffffff)>>j0;
00072               if(((i0&i)|i1)==0) return x; /* x is integral */
00073               i>>=1;
00074               if(((i0&i)|i1)!=0) {
00075                   if (j0==30) i1 = 0x40000000; else
00076                   i0 = (i0&(~i))|((0x20000000)>>j0);
00077               }
00078            }
00079        } else if (j0>62) {
00080            if(j0==0x4000) return x+x;     /* inf or NaN */
00081            else return x;          /* x is integral */
00082        } else {
00083            i = ((u_int32_t)(0xffffffff))>>(j0-31);
00084            if((i1&i)==0) return x; /* x is integral */
00085            i>>=1;
00086            if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-31));
00087        }
00088        SET_LDOUBLE_WORDS(x,se,i0,i1);
00089        feholdexcept (&env);
00090        w = TWO63[sx]+x;
00091        t = w-TWO63[sx];
00092        fesetenv (&env);
00093        return t;
00094 }
00095 weak_alias (__nearbyintl, nearbyintl)