1132451Sroberto/* @(#)s_rint.c 5.1 93/09/24 */
2132451Sroberto/*
3132451Sroberto * ====================================================
4132451Sroberto * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5132451Sroberto *
6132451Sroberto * Developed at SunPro, a Sun Microsystems, Inc. business.
7132451Sroberto * Permission to use, copy, modify, and distribute this
8132451Sroberto * software is freely granted, provided that this notice
9132451Sroberto * is preserved.
10132451Sroberto * ====================================================
11132451Sroberto */
12132451Sroberto
13132451Sroberto/*
14132451Sroberto * rint(x)
15132451Sroberto * Return x rounded to integral value according to the prevailing
16132451Sroberto * rounding mode.
17132451Sroberto * Method:
18132451Sroberto *	Using floating addition.
19132451Sroberto * Exception:
20132451Sroberto *	Inexact flag raised if x not equal to rint(x).
21132451Sroberto */
22132451Sroberto
23132451Sroberto#include <float.h>
24132451Sroberto#include <math.h>
25132451Sroberto
26132451Sroberto#include "math_private.h"
27132451Sroberto
28132451Srobertostatic const double
29132451SrobertoTWO52[2]={
30132451Sroberto  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
31132451Sroberto -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
32132451Sroberto};
33132451Sroberto
34132451Srobertodouble
35132451Srobertorint(double x)
36132451Sroberto{
37132451Sroberto	int32_t i0,jj0,sx;
38132451Sroberto	u_int32_t i,i1;
39132451Sroberto	double t;
40132451Sroberto	volatile double w;	/* clip extra precision */
41132451Sroberto	EXTRACT_WORDS(i0,i1,x);
42132451Sroberto	sx = (i0>>31)&1;
43132451Sroberto	jj0 = ((i0>>20)&0x7ff)-0x3ff;
44132451Sroberto	if(jj0<20) {
45132451Sroberto	    if(jj0<0) {
46132451Sroberto		if(((i0&0x7fffffff)|i1)==0) return x;
47132451Sroberto		i1 |= (i0&0x0fffff);
48132451Sroberto		i0 &= 0xfffe0000;
49132451Sroberto		i0 |= ((i1|-i1)>>12)&0x80000;
50132451Sroberto		SET_HIGH_WORD(x,i0);
51132451Sroberto	        w = TWO52[sx]+x;
52132451Sroberto	        t =  w-TWO52[sx];
53132451Sroberto		GET_HIGH_WORD(i0,t);
54132451Sroberto		SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
55132451Sroberto	        return t;
56132451Sroberto	    } else {
57132451Sroberto		i = (0x000fffff)>>jj0;
58132451Sroberto		if(((i0&i)|i1)==0) return x; /* x is integral */
59132451Sroberto		i>>=1;
60132451Sroberto		if(((i0&i)|i1)!=0) {
61132451Sroberto		    if(jj0==19) i1 = 0x40000000; else
62132451Sroberto		    i0 = (i0&(~i))|((0x20000)>>jj0);
63132451Sroberto		}
64132451Sroberto	    }
65132451Sroberto	} else if (jj0>51) {
66132451Sroberto	    if(jj0==0x400) return x+x;	/* inf or NaN */
67132451Sroberto	    else return x;		/* x is integral */
68132451Sroberto	} else {
69132451Sroberto	    i = ((u_int32_t)(0xffffffff))>>(jj0-20);
70132451Sroberto	    if((i1&i)==0) return x;	/* x is integral */
71132451Sroberto	    i>>=1;
72132451Sroberto	    if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(jj0-20));
73132451Sroberto	}
74132451Sroberto	INSERT_WORDS(x,i0,i1);
75132451Sroberto	w = TWO52[sx]+x;
76132451Sroberto	return w-TWO52[sx];
77132451Sroberto}
78132451SrobertoDEF_STD(rint);
79132451SrobertoLDBL_MAYBE_NONSTD_CLONE(rint);
80132451Sroberto