Welcome to mirror list, hosted at ThFree Co, Russian Federation.

s_rint.c « common « libm « newlib - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 7dce9f52bab6c3da73f249e12812c43ff2dd4be4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

/* @(#)s_rint.c 5.1 93/09/24 */
/*
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
 * software is freely granted, provided that this notice 
 * is preserved.
 * ====================================================
 */
/*
FUNCTION
<<rint>>, <<rintf>>---round to integer
INDEX
	rint
INDEX
	rintf

SYNOPSIS
	#include <math.h>
	double rint(double <[x]>);
	float rintf(float <[x]>);

DESCRIPTION
	The <<rint>> functions round their argument to an integer value in
	floating-point format, using the current rounding direction.  They
	raise the "inexact" floating-point exception if the result differs
	in value from the argument.  See the <<nearbyint>> functions for the
	same function with the "inexact" floating-point exception never being
	raised.  Newlib does not directly support floating-point exceptions.
	The <<rint>> functions are written so that the "inexact" exception is
	raised in hardware implementations that support it, even though Newlib
	does not provide access.

RETURNS
<[x]> rounded to an integral value, using the current rounding direction.

PORTABILITY
ANSI C, POSIX

SEEALSO
<<nearbyint>>, <<round>>

*/

/*
 * rint(x)
 * Return x rounded to integral value according to the prevailing
 * rounding mode.
 * Method:
 *	Using floating addition.
 *	Whenever a fraction is present, if the second or any following bit after
 *	the radix point is set, limit to the second radix point to avoid
 *	possible double rounding in the TWO52 +- steps (in case guard bits are
 *	used).  Specifically, if have any, chop off bits past the 2nd place and
 *	set the second place.
 *	(e.g.	2.0625=0b10.0001 => 0b10.01=2.25;
 *		2.3125=0b10.011  => 0b10.01=2.25;
 *		1.5625= 0b1.1001 =>  0b1.11=1.75;
 *		1.9375= 0b1.1111 =>  0b1.11=1.75.
 *	Pseudo-code:  if(x.frac & ~0b0.10) x.frac = (x.frac & 0b0.11) | 0b0.01;).
 * Exception:
 *	Inexact flag raised if x not equal to rint(x).
 */

#include "fdlibm.h"

#ifndef _DOUBLE_IS_32BITS

#ifdef __STDC__
static const double
#else
static double 
#endif
TWO52[2]={
  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
 -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
};

#ifdef __STDC__
	double rint(double x)
#else
	double rint(x)
	double x;
#endif
{
	__int32_t i0,j0,sx;
	__uint32_t i,i1;
	double t;
	volatile double w;
	EXTRACT_WORDS(i0,i1,x);
	sx = (i0>>31)&1;		/* sign */
	j0 = ((i0>>20)&0x7ff)-0x3ff;	/* exponent */
	if(j0<20) {			/* no integral bits in LS part */
	    if(j0<0) { 			/* x is fractional or 0 */
		if(((i0&0x7fffffff)|i1)==0) return x;	/* x == 0 */
		i1 |= (i0&0x0fffff);
		i0 &= 0xfffe0000;
		i0 |= ((i1|-i1)>>12)&0x80000;
		SET_HIGH_WORD(x,i0);
	        w = TWO52[sx]+x;
	        t =  w-TWO52[sx];
		GET_HIGH_WORD(i0,t);
		SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
	        return t;
	    } else {			/* x has integer and maybe fraction */
		i = (0x000fffff)>>j0;
		if(((i0&i)|i1)==0) return x; /* x is integral */
		i>>=1;
		if(((i0&i)|i1)!=0) {
		    /* 2nd or any later bit after radix is set */
		    if(j0==19) i1 = 0x80000000; else i1 = 0;
		    i0 = (i0&(~i))|((0x40000)>>j0);
		}
	    }
	} else if (j0>51) {
	    if(j0==0x400) return x+x;	/* inf or NaN */
	    else return x;		/* x is integral */
	} else {
	    i = ((__uint32_t)(0xffffffff))>>(j0-20);
	    if((i1&i)==0) return x;	/* x is integral */
	    i>>=1;
	    if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
	}
	INSERT_WORDS(x,i0,i1);
	w = TWO52[sx]+x;
	return w-TWO52[sx];
}

#endif /* _DOUBLE_IS_32BITS */