OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / uClibc / libm / s_rint.c
1 /*
2  * ====================================================
3  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
4  *
5  * Developed at SunPro, a Sun Microsystems, Inc. business.
6  * Permission to use, copy, modify, and distribute this
7  * software is freely granted, provided that this notice
8  * is preserved.
9  * ====================================================
10  */
11
12 /*
13  * rint(x)
14  * Return x rounded to integral value according to the prevailing
15  * rounding mode.
16  * Method:
17  *      Using floating addition.
18  * Exception:
19  *      Inexact flag raised if x not equal to rint(x).
20  */
21
22 #include "math.h"
23 #include "math_private.h"
24
25 static const double
26 TWO52[2]={
27   4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
28  -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
29 };
30
31 double rint(double x)
32 {
33         int32_t i0, j0, sx;
34         u_int32_t i,i1;
35         double t;
36         /* We use w = x + 2^52; t = w - 2^52; trick to round x to integer.
37          * This trick requires that compiler does not optimize it
38          * by keeping intermediate result w in a register wider than double.
39          * Declaring w volatile assures that value gets truncated to double
40          * (unfortunately, it also forces store+load):
41          */
42         volatile double w;
43
44         EXTRACT_WORDS(i0,i1,x);
45         /* Unbiased exponent */
46         j0 = ((((u_int32_t)i0) >> 20)&0x7ff)-0x3ff;
47
48         if (j0 > 51) {
49                 //Why bother? Just returning x works too
50                 //if (j0 == 0x400)  /* inf or NaN */
51                 //      return x+x;
52                 return x;  /* x is integral */
53         }
54
55         /* Sign */
56         sx = ((u_int32_t)i0) >> 31;
57
58         if (j0<20) {
59             if (j0<0) { /* |x| < 1 */
60                 if (((i0&0x7fffffff)|i1)==0) return x;
61                 i1 |= (i0&0x0fffff);
62                 i0 &= 0xfffe0000;
63                 i0 |= ((i1|-i1)>>12)&0x80000;
64                 SET_HIGH_WORD(x,i0);
65                 w = TWO52[sx]+x;
66                 t = w-TWO52[sx];
67                 GET_HIGH_WORD(i0,t);
68                 SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
69                 return t;
70             } else {
71                 i = (0x000fffff)>>j0;
72                 if (((i0&i)|i1)==0) return x; /* x is integral */
73                 i>>=1;
74                 if (((i0&i)|i1)!=0) {
75                     if (j0==19) i1 = 0x40000000;
76                     else i0 = (i0&(~i))|((0x20000)>>j0);
77                 }
78             }
79         } else {
80             i = ((u_int32_t)(0xffffffff))>>(j0-20);
81             if ((i1&i)==0) return x;    /* x is integral */
82             i>>=1;
83             if ((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
84         }
85         INSERT_WORDS(x,i0,i1);
86         w = TWO52[sx]+x;
87         return w-TWO52[sx];
88 }
89 libm_hidden_def(rint)
90
91 strong_alias(rint, nearbyint)
92 libm_hidden_def(nearbyint)