1*25c28e83SPiotr Jasiukajtis /*
2*25c28e83SPiotr Jasiukajtis  * CDDL HEADER START
3*25c28e83SPiotr Jasiukajtis  *
4*25c28e83SPiotr Jasiukajtis  * The contents of this file are subject to the terms of the
5*25c28e83SPiotr Jasiukajtis  * Common Development and Distribution License (the "License").
6*25c28e83SPiotr Jasiukajtis  * You may not use this file except in compliance with the License.
7*25c28e83SPiotr Jasiukajtis  *
8*25c28e83SPiotr Jasiukajtis  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25c28e83SPiotr Jasiukajtis  * or http://www.opensolaris.org/os/licensing.
10*25c28e83SPiotr Jasiukajtis  * See the License for the specific language governing permissions
11*25c28e83SPiotr Jasiukajtis  * and limitations under the License.
12*25c28e83SPiotr Jasiukajtis  *
13*25c28e83SPiotr Jasiukajtis  * When distributing Covered Code, include this CDDL HEADER in each
14*25c28e83SPiotr Jasiukajtis  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25c28e83SPiotr Jasiukajtis  * If applicable, add the following below this CDDL HEADER, with the
16*25c28e83SPiotr Jasiukajtis  * fields enclosed by brackets "[]" replaced with your own identifying
17*25c28e83SPiotr Jasiukajtis  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25c28e83SPiotr Jasiukajtis  *
19*25c28e83SPiotr Jasiukajtis  * CDDL HEADER END
20*25c28e83SPiotr Jasiukajtis  */
21*25c28e83SPiotr Jasiukajtis 
22*25c28e83SPiotr Jasiukajtis /*
23*25c28e83SPiotr Jasiukajtis  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24*25c28e83SPiotr Jasiukajtis  */
25*25c28e83SPiotr Jasiukajtis /*
26*25c28e83SPiotr Jasiukajtis  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27*25c28e83SPiotr Jasiukajtis  * Use is subject to license terms.
28*25c28e83SPiotr Jasiukajtis  */
29*25c28e83SPiotr Jasiukajtis 
30*25c28e83SPiotr Jasiukajtis #pragma weak nearbyintl = __nearbyintl
31*25c28e83SPiotr Jasiukajtis 
32*25c28e83SPiotr Jasiukajtis #include "libm.h"
33*25c28e83SPiotr Jasiukajtis #include "fma.h"
34*25c28e83SPiotr Jasiukajtis #include "fenv_inlines.h"
35*25c28e83SPiotr Jasiukajtis 
36*25c28e83SPiotr Jasiukajtis #if defined(__sparc)
37*25c28e83SPiotr Jasiukajtis 
38*25c28e83SPiotr Jasiukajtis static union {
39*25c28e83SPiotr Jasiukajtis 	unsigned i;
40*25c28e83SPiotr Jasiukajtis 	float f;
41*25c28e83SPiotr Jasiukajtis } snan = { 0x7f800001 };
42*25c28e83SPiotr Jasiukajtis 
43*25c28e83SPiotr Jasiukajtis long double
__nearbyintl(long double x)44*25c28e83SPiotr Jasiukajtis __nearbyintl(long double x) {
45*25c28e83SPiotr Jasiukajtis 	union {
46*25c28e83SPiotr Jasiukajtis 		unsigned i[4];
47*25c28e83SPiotr Jasiukajtis 		long double q;
48*25c28e83SPiotr Jasiukajtis 	} xx;
49*25c28e83SPiotr Jasiukajtis 	unsigned hx, sx, i, frac;
50*25c28e83SPiotr Jasiukajtis 	unsigned int fsr;
51*25c28e83SPiotr Jasiukajtis 	int rm, j;
52*25c28e83SPiotr Jasiukajtis 	volatile float	dummy;
53*25c28e83SPiotr Jasiukajtis 
54*25c28e83SPiotr Jasiukajtis 	xx.q = x;
55*25c28e83SPiotr Jasiukajtis 	sx = xx.i[0] & 0x80000000;
56*25c28e83SPiotr Jasiukajtis 	hx = xx.i[0] & ~0x80000000;
57*25c28e83SPiotr Jasiukajtis 
58*25c28e83SPiotr Jasiukajtis 	/* handle trivial cases */
59*25c28e83SPiotr Jasiukajtis 	if (hx >= 0x406f0000) {	/* x is nan, inf, or already integral */
60*25c28e83SPiotr Jasiukajtis 		/* check for signaling nan */
61*25c28e83SPiotr Jasiukajtis 		if ((hx > 0x7fff0000 || (hx == 0x7fff0000 &&
62*25c28e83SPiotr Jasiukajtis 			(xx.i[1] | xx.i[2] | xx.i[3]))) && !(hx & 0x8000)) {
63*25c28e83SPiotr Jasiukajtis 			dummy = snan.f;
64*25c28e83SPiotr Jasiukajtis 			dummy += snan.f;
65*25c28e83SPiotr Jasiukajtis 			xx.i[0] = sx | hx | 0x8000;
66*25c28e83SPiotr Jasiukajtis 		}
67*25c28e83SPiotr Jasiukajtis 		return (xx.q);
68*25c28e83SPiotr Jasiukajtis 	} else if ((hx | xx.i[1] | xx.i[2] | xx.i[3]) == 0)	/* x is zero */
69*25c28e83SPiotr Jasiukajtis 		return (x);
70*25c28e83SPiotr Jasiukajtis 
71*25c28e83SPiotr Jasiukajtis 	/* get the rounding mode */
72*25c28e83SPiotr Jasiukajtis 	__fenv_getfsr32(&fsr);
73*25c28e83SPiotr Jasiukajtis 	rm = fsr >> 30;
74*25c28e83SPiotr Jasiukajtis 
75*25c28e83SPiotr Jasiukajtis 	/* flip the sense of directed roundings if x is negative */
76*25c28e83SPiotr Jasiukajtis 	if (sx)
77*25c28e83SPiotr Jasiukajtis 		rm ^= rm >> 1;
78*25c28e83SPiotr Jasiukajtis 
79*25c28e83SPiotr Jasiukajtis 	/* handle |x| < 1 */
80*25c28e83SPiotr Jasiukajtis 	if (hx < 0x3fff0000) {
81*25c28e83SPiotr Jasiukajtis 		if (rm == FSR_RP || (rm == FSR_RN && (hx >= 0x3ffe0000 &&
82*25c28e83SPiotr Jasiukajtis 			((hx & 0xffff) | xx.i[1] | xx.i[2] | xx.i[3]))))
83*25c28e83SPiotr Jasiukajtis 			xx.i[0] = sx | 0x3fff0000;
84*25c28e83SPiotr Jasiukajtis 		else
85*25c28e83SPiotr Jasiukajtis 			xx.i[0] = sx;
86*25c28e83SPiotr Jasiukajtis 		xx.i[1] = xx.i[2] = xx.i[3] = 0;
87*25c28e83SPiotr Jasiukajtis 		return (xx.q);
88*25c28e83SPiotr Jasiukajtis 	}
89*25c28e83SPiotr Jasiukajtis 
90*25c28e83SPiotr Jasiukajtis 	/* round x at the integer bit */
91*25c28e83SPiotr Jasiukajtis 	j = 0x406f - (hx >> 16);
92*25c28e83SPiotr Jasiukajtis 	if (j >= 96) {
93*25c28e83SPiotr Jasiukajtis 		i = 1 << (j - 96);
94*25c28e83SPiotr Jasiukajtis 		frac = ((xx.i[0] << 1) << (127 - j)) | (xx.i[1] >> (j - 96));
95*25c28e83SPiotr Jasiukajtis 		if ((xx.i[1] & (i - 1)) | xx.i[2] | xx.i[3])
96*25c28e83SPiotr Jasiukajtis 			frac |= 1;
97*25c28e83SPiotr Jasiukajtis 		if (!frac)
98*25c28e83SPiotr Jasiukajtis 			return (x);
99*25c28e83SPiotr Jasiukajtis 		xx.i[1] = xx.i[2] = xx.i[3] = 0;
100*25c28e83SPiotr Jasiukajtis 		xx.i[0] &= ~(i - 1);
101*25c28e83SPiotr Jasiukajtis 		if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u ||
102*25c28e83SPiotr Jasiukajtis 			(frac == 0x80000000 && (xx.i[0] & i)))))
103*25c28e83SPiotr Jasiukajtis 			xx.i[0] += i;
104*25c28e83SPiotr Jasiukajtis 	} else if (j >= 64) {
105*25c28e83SPiotr Jasiukajtis 		i = 1 << (j - 64);
106*25c28e83SPiotr Jasiukajtis 		frac = ((xx.i[1] << 1) << (95 - j)) | (xx.i[2] >> (j - 64));
107*25c28e83SPiotr Jasiukajtis 		if ((xx.i[2] & (i - 1)) | xx.i[3])
108*25c28e83SPiotr Jasiukajtis 			frac |= 1;
109*25c28e83SPiotr Jasiukajtis 		if (!frac)
110*25c28e83SPiotr Jasiukajtis 			return (x);
111*25c28e83SPiotr Jasiukajtis 		xx.i[2] = xx.i[3] = 0;
112*25c28e83SPiotr Jasiukajtis 		xx.i[1] &= ~(i - 1);
113*25c28e83SPiotr Jasiukajtis 		if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u ||
114*25c28e83SPiotr Jasiukajtis 			(frac == 0x80000000 && (xx.i[1] & i))))) {
115*25c28e83SPiotr Jasiukajtis 			xx.i[1] += i;
116*25c28e83SPiotr Jasiukajtis 			if (xx.i[1] == 0)
117*25c28e83SPiotr Jasiukajtis 				xx.i[0]++;
118*25c28e83SPiotr Jasiukajtis 		}
119*25c28e83SPiotr Jasiukajtis 	} else if (j >= 32) {
120*25c28e83SPiotr Jasiukajtis 		i = 1 << (j - 32);
121*25c28e83SPiotr Jasiukajtis 		frac = ((xx.i[2] << 1) << (63 - j)) | (xx.i[3] >> (j - 32));
122*25c28e83SPiotr Jasiukajtis 		if (xx.i[3] & (i - 1))
123*25c28e83SPiotr Jasiukajtis 			frac |= 1;
124*25c28e83SPiotr Jasiukajtis 		if (!frac)
125*25c28e83SPiotr Jasiukajtis 			return (x);
126*25c28e83SPiotr Jasiukajtis 		xx.i[3] = 0;
127*25c28e83SPiotr Jasiukajtis 		xx.i[2] &= ~(i - 1);
128*25c28e83SPiotr Jasiukajtis 		if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u ||
129*25c28e83SPiotr Jasiukajtis 			(frac == 0x80000000 && (xx.i[2] & i))))) {
130*25c28e83SPiotr Jasiukajtis 			xx.i[2] += i;
131*25c28e83SPiotr Jasiukajtis 			if (xx.i[2] == 0)
132*25c28e83SPiotr Jasiukajtis 				if (++xx.i[1] == 0)
133*25c28e83SPiotr Jasiukajtis 					xx.i[0]++;
134*25c28e83SPiotr Jasiukajtis 		}
135*25c28e83SPiotr Jasiukajtis 	} else {
136*25c28e83SPiotr Jasiukajtis 		i = 1 << j;
137*25c28e83SPiotr Jasiukajtis 		frac = (xx.i[3] << 1) << (31 - j);
138*25c28e83SPiotr Jasiukajtis 		if (!frac)
139*25c28e83SPiotr Jasiukajtis 			return (x);
140*25c28e83SPiotr Jasiukajtis 		xx.i[3] &= ~(i - 1);
141*25c28e83SPiotr Jasiukajtis 		if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u ||
142*25c28e83SPiotr Jasiukajtis 			(frac == 0x80000000 && (xx.i[3] & i))))) {
143*25c28e83SPiotr Jasiukajtis 			xx.i[3] += i;
144*25c28e83SPiotr Jasiukajtis 			if (xx.i[3] == 0)
145*25c28e83SPiotr Jasiukajtis 				if (++xx.i[2] == 0)
146*25c28e83SPiotr Jasiukajtis 					if (++xx.i[1] == 0)
147*25c28e83SPiotr Jasiukajtis 						xx.i[0]++;
148*25c28e83SPiotr Jasiukajtis 		}
149*25c28e83SPiotr Jasiukajtis 	}
150*25c28e83SPiotr Jasiukajtis 
151*25c28e83SPiotr Jasiukajtis 	return (xx.q);
152*25c28e83SPiotr Jasiukajtis }
153*25c28e83SPiotr Jasiukajtis 
154*25c28e83SPiotr Jasiukajtis #elif defined(__x86)
155*25c28e83SPiotr Jasiukajtis 
156*25c28e83SPiotr Jasiukajtis /* inline template */
157*25c28e83SPiotr Jasiukajtis extern long double frndint(long double);
158*25c28e83SPiotr Jasiukajtis 
159*25c28e83SPiotr Jasiukajtis long double
__nearbyintl(long double x)160*25c28e83SPiotr Jasiukajtis __nearbyintl(long double x) {
161*25c28e83SPiotr Jasiukajtis 	long double z;
162*25c28e83SPiotr Jasiukajtis 	unsigned oldcwsw, cwsw;
163*25c28e83SPiotr Jasiukajtis 
164*25c28e83SPiotr Jasiukajtis 	/* save the control and status words, mask the inexact exception */
165*25c28e83SPiotr Jasiukajtis 	__fenv_getcwsw(&oldcwsw);
166*25c28e83SPiotr Jasiukajtis 	cwsw = oldcwsw | 0x00200000;
167*25c28e83SPiotr Jasiukajtis 	__fenv_setcwsw(&cwsw);
168*25c28e83SPiotr Jasiukajtis 
169*25c28e83SPiotr Jasiukajtis 	z = frndint(x);
170*25c28e83SPiotr Jasiukajtis 
171*25c28e83SPiotr Jasiukajtis 	/*
172*25c28e83SPiotr Jasiukajtis 	 * restore the control and status words, preserving all but the
173*25c28e83SPiotr Jasiukajtis 	 * inexact flag
174*25c28e83SPiotr Jasiukajtis 	 */
175*25c28e83SPiotr Jasiukajtis 	__fenv_getcwsw(&cwsw);
176*25c28e83SPiotr Jasiukajtis 	oldcwsw |= (cwsw & 0x1f);
177*25c28e83SPiotr Jasiukajtis 	__fenv_setcwsw(&oldcwsw);
178*25c28e83SPiotr Jasiukajtis 
179*25c28e83SPiotr Jasiukajtis 	return (z);
180*25c28e83SPiotr Jasiukajtis }
181*25c28e83SPiotr Jasiukajtis 
182*25c28e83SPiotr Jasiukajtis #else
183*25c28e83SPiotr Jasiukajtis #error Unknown architecture
184*25c28e83SPiotr Jasiukajtis #endif
185