OSDN Git Service

* math/rem_pio2q.c (__quadmath_kernel_rem_pio2): Fix up fq to y
[pf3gnuchains/gcc-fork.git] / libquadmath / math / nearbyintq.c
1 /* nearbyintq.c -- __float128 version of s_nearbyint.c.
2  * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
3  */
4
5 /*
6  * ====================================================
7  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
8  *
9  * Developed at SunPro, a Sun Microsystems, Inc. business.
10  * Permission to use, copy, modify, and distribute this
11  * software is freely granted, provided that this notice
12  * is preserved.
13  * ====================================================
14  */
15
16 /*
17  * nearbyintq(x)
18  * Return x rounded to integral value according to the prevailing
19  * rounding mode.
20  * Method:
21  *      Using floating addition.
22  * Exception:
23  *      Inexact flag raised if x not equal to rintq(x).
24  */
25
26 #include "quadmath-imp.h"
27 #ifdef HAVE_FENV_H
28 # include <fenv.h>
29 # if defined HAVE_FEHOLDEXCEPT && defined HAVE_FESETENV
30 #   define USE_FENV_H
31 # endif
32 #endif
33
34 static const __float128
35 TWO112[2]={
36   5.19229685853482762853049632922009600E+33Q, /* 0x406F000000000000, 0 */
37  -5.19229685853482762853049632922009600E+33Q  /* 0xC06F000000000000, 0 */
38 };
39
40 __float128
41 nearbyintq(__float128 x)
42 {
43 #ifdef USE_FENV_H
44         fenv_t env;
45 #endif
46         int64_t i0,j0,sx;
47         uint64_t i,i1;
48         __float128 w,t;
49         GET_FLT128_WORDS64(i0,i1,x);
50         sx = (((uint64_t)i0)>>63);
51         j0 = ((i0>>48)&0x7fff)-0x3fff;
52         if(j0<48) {
53             if(j0<0) {
54                 if(((i0&0x7fffffffffffffffLL)|i1)==0) return x;
55                 i1 |= (i0&0x0000ffffffffffffLL);
56                 i0 &= 0xffffe00000000000ULL;
57                 i0 |= ((i1|-i1)>>16)&0x0000800000000000LL;
58                 SET_FLT128_MSW64(x,i0);
59 #ifdef USE_FENV_H
60                 feholdexcept (&env);
61 #endif
62                 w = TWO112[sx]+x;
63                 t = w-TWO112[sx];
64 #ifdef USE_FENV_H
65                 fesetenv (&env);
66 #endif
67                 GET_FLT128_MSW64(i0,t);
68                 SET_FLT128_MSW64(t,(i0&0x7fffffffffffffffLL)|(sx<<63));
69                 return t;
70             } else {
71                 i = (0x0000ffffffffffffLL)>>j0;
72                 if(((i0&i)|i1)==0) return x; /* x is integral */
73                 i>>=1;
74                 if(((i0&i)|i1)!=0) {
75                     if(j0==47) i1 = 0x4000000000000000ULL; else
76                     i0 = (i0&(~i))|((0x0000200000000000LL)>>j0);
77                 }
78             }
79         } else if (j0>111) {
80             if(j0==0x4000) return x+x;  /* inf or NaN */
81             else return x;              /* x is integral */
82         } else {
83             i = -1ULL>>(j0-48);
84             if((i1&i)==0) return x;     /* x is integral */
85             i>>=1;
86             if((i1&i)!=0) i1 = (i1&(~i))|((0x4000000000000000LL)>>(j0-48));
87         }
88         SET_FLT128_WORDS64(x,i0,i1);
89 #ifdef USE_FENV_H
90         feholdexcept (&env);
91 #endif
92         w = TWO112[sx]+x;
93         t = w-TWO112[sx];
94 #ifdef USE_FENV_H       
95         fesetenv (&env);
96 #endif
97         return t;
98 }