xref: /illumos-gate/usr/src/lib/libc/port/gen/_ftoull.c (revision 2a6e99a0f1f7d22c0396e8b2ce9b9babbd1056cf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "lint.h"
30 #include <sys/isa_defs.h>
31 #include <floatingpoint.h>
32 #include <limits.h>
33 #include "libc.h"
34 
35 /*
36  * Ensure that this "portable" code is only used on big-endian ISAs
37  */
38 #if !defined(_BIG_ENDIAN) || defined(_LITTLE_ENDIAN)
39 #error	"big-endian only!"
40 #endif
41 
42 /*
43  * Convert a double precision floating point # into a 64-bit unsigned int.
44  *
45  * For compatibility with Sun's other conversion routines, pretend result
46  * is signed if input is negative.
47  */
48 unsigned long long
49 __dtoull(double dval)
50 {
51 	int i0;			/* bitslam */
52 	unsigned i1;		/* bitslam */
53 	int exp;		/* exponent */
54 	unsigned int m0;	/* most significant word of mantissa */
55 	unsigned int m1;	/* least sig. word of mantissa */
56 	unsigned int _fp_current_exceptions = 0;
57 	union {
58 		int i[2];
59 		double d;
60 	} u;
61 
62 	/*
63 	 * Extract the exponent and check boundary conditions.
64 	 * Notice that the exponent is equal to the bit number where
65 	 * we want the most significant bit to live.
66 	 */
67 	u.d = dval;
68 	i0 = u.i[0];
69 	i1 = u.i[1];
70 
71 	exp = ((i0 >> 20) & 0x7ff) - 0x3ff;
72 	if (exp < 0) {
73 		/* abs(x) < 1.0, so round to 0 */
74 		return ((unsigned long long)0);
75 	} else if (exp > 63)  {
76 		/*
77 		 * abs(x) > MAXLLONG; return {MIN,MAX}ULLONG and as
78 		 * overflow, Inf, NaN set fp_invalid exception
79 		 */
80 		_fp_current_exceptions |= (1 << (int)fp_invalid);
81 		(void) _Q_set_exception(_fp_current_exceptions);
82 		if (i0 < 0)
83 			return ((unsigned long long)LLONG_MIN);
84 		else
85 			return (ULLONG_MAX); /* MAXLONG */
86 	}
87 
88 	/* Extract the mantissa. */
89 
90 	m0 = 0x80000000 | ((i0 << 11) & 0x7ffff800) | ((i1 >> 21) & 0x7ff);
91 	m1 = i1 << 11;
92 
93 	/*
94 	 * The most significant bit of the mantissa is now in bit 63 of m0:m1.
95 	 * Shift right by (63 - exp) bits.
96 	 */
97 	switch (exp) {
98 	case 63:
99 		break;
100 	case 31:
101 		m1 = m0;
102 		m0 = 0;
103 		break;
104 	default:
105 		if (exp > 31) {
106 			m1 = (m0 << (exp - 31)) | (m1 >> (63 - exp));
107 			m0 = (m0 >> (63 - exp));
108 		} else {
109 			m1 = (m0 >> (31 - exp));
110 			m0 = 0;
111 		}
112 		break;
113 	}
114 
115 	if (i0 < 0) {
116 		if ((int)m0 < 0) {	/* x < MINLLONG; return MINLLONG */
117 			m0 = 0x80000000;
118 			m1 = 0;
119 		} else {
120 			m0 = ~m0;
121 			m1 = ~m1;
122 			if (++m1 == 0)
123 				m0++;
124 		}
125 	}
126 
127 	(void) _Q_set_exception(_fp_current_exceptions);
128 	return (((unsigned long long)m0 << 32) | m1);
129 }
130 
131 /*
132  * Convert a floating point number into a 64-bit unsigned int.
133  *
134  * For compatibility with Sun's other conversion routines, pretend result
135  * is signed if input is negative.
136  */
137 unsigned long long
138 __ftoull(float fval)
139 {
140 	int i0;			/* bitslam */
141 	int exp;		/* exponent */
142 	unsigned int m0;	/* most significant word of mantissa */
143 	unsigned int m1;	/* least sig. word of mantissa */
144 	unsigned int _fp_current_exceptions = 0;
145 	union {
146 		int i;
147 		float f;
148 	} u;
149 
150 	/*
151 	 * Extract the exponent and check boundary conditions.
152 	 * Notice that the exponent is equal to the bit number where
153 	 * we want the most significant bit to live.
154 	 */
155 	u.f = fval;
156 	i0 = u.i;
157 
158 	exp = ((i0 >> 23) & 0xff) - 0x7f;
159 	if (exp < 0) {
160 		/* abs(x) < 1.0, so round to 0 */
161 		return ((unsigned long long)0);
162 	} else if (exp > 63)  {
163 		/*
164 		 * abs(x) > MAXLLONG; return {MIN,MAX}ULLONG and as
165 		 * overflow, Inf, NaN set fp_invalid exception
166 		 */
167 		_fp_current_exceptions |= (1 << (int)fp_invalid);
168 		(void) _Q_set_exception(_fp_current_exceptions);
169 		if (i0 < 0)
170 			return ((unsigned long long)LLONG_MIN);
171 		else
172 			return (ULLONG_MAX); /* MAXLONG */
173 	}
174 
175 	/* Extract the mantissa. */
176 
177 	m0 = 0x80000000 | (i0 << 8) & 0x7fffff00;
178 	m1 = 0;
179 
180 	/*
181 	 * The most significant bit of the mantissa is now in bit 63 of m0:m1.
182 	 * Shift right by (63 - exp) bits.
183 	 */
184 	switch (exp) {
185 	case 63:
186 		break;
187 	case 31:
188 		m1 = m0;
189 		m0 = 0;
190 		break;
191 	default:
192 		if (exp > 31) {
193 			m1 = m0 << (exp - 31);
194 			m0 = (m0 >> (63 - exp));
195 		} else {
196 			m1 = (m0 >> (31 - exp));
197 			m0 = 0;
198 		}
199 		break;
200 	}
201 
202 	if (i0 < 0) {
203 		if ((int)m0 < 0) {	/* x < MINLLONG; return MINLLONG */
204 			m0 = 0x80000000;
205 			m1 = 0;
206 		} else {
207 			m0 = ~m0;
208 			m1 = ~m1;
209 			if (++m1 == 0)
210 				m0++;
211 		}
212 	}
213 
214 	(void) _Q_set_exception(_fp_current_exceptions);
215 	return (((unsigned long long)m0 << 32) | m1);
216 }
217 
218 /*
219  * Convert an extended precision floating point # into a 64-bit unsigned int.
220  *
221  * For compatibility with Sun's other conversion routines, pretend result
222  * is signed if input is negative.
223  */
224 unsigned long long
225 _Q_qtoull(long double ld)
226 {
227 	int i0;
228 	unsigned int i1, i2;	/* a long double is 128-bit in length */
229 	int exp;		/* exponent */
230 	unsigned int m0;	/* most significant word of mantissa */
231 	unsigned int m1;	/* least sig. word of mantissa */
232 	unsigned int _fp_current_exceptions = 0;
233 	int	 *plngdbl = (int *)&ld;
234 
235 	/* Only 96-bits of precision used */
236 	i0 = plngdbl[0];
237 	i1 = plngdbl[1];
238 	i2 = plngdbl[2];
239 
240 	/*
241 	 * Extract the exponent and check boundary conditions.
242 	 * Notice that the exponent is equal to the bit number where
243 	 * we want the most significant bit to live.
244 	 */
245 	exp = ((i0 >> 16) & 0x7fff) - 0x3fff;
246 	if (exp < 0) {
247 		return ((long long)0); /* abs(x) < 1.0, so round to 0 */
248 	} else if (exp > 63) {
249 		/*
250 		 * abs(x) > MAXLLONG; return {MIN,MAX}ULLONG and as
251 		 * overflow, Inf, NaN set fp_invalid exception
252 		 */
253 		_fp_current_exceptions |= (1 << (int)fp_invalid);
254 		(void) _Q_set_exception(_fp_current_exceptions);
255 		if (i0 < 0)
256 			return ((unsigned long long)LLONG_MIN);
257 		else
258 			return (ULLONG_MAX); /* MAXLONG */
259 	}
260 
261 	/* Extract the mantissa. */
262 
263 	m0 = 0x80000000 | ((i0<<15) & 0x7fff8000) | ((i1>>17) & 0x7fff);
264 	m1 = (i1 << 15) | ((i2 >> 17) & 0x7fff);
265 
266 	/*
267 	 * The most significant bit of the mantissa is now in bit 63 of m0:m1.
268 	 * Shift right by (63 - exp) bits.
269 	 */
270 	switch (exp) {
271 	case 63:
272 		break;
273 	case 31:
274 		m1 = m0;
275 		m0 = 0;
276 		break;
277 	default:
278 		if (exp > 31) {
279 			m1 = (m0 << (exp - 31)) | (m1 >> (63 - exp));
280 			m0 = (m0 >> (63 - exp));
281 		} else {
282 			m1 = (m0 >> (31 - exp));
283 			m0 = 0;
284 		}
285 		break;
286 	}
287 
288 	if (i0 < 0) {
289 		if ((int)m0 < 0) {	/* x < MINLLONG; return MINLLONG */
290 			m0 = 0x80000000;
291 			m1 = 0;
292 		} else {
293 			m0 = ~m0;
294 			m1 = ~m1;
295 			if (++m1 == 0)
296 				m0++;
297 		}
298 	}
299 
300 	(void) _Q_set_exception(_fp_current_exceptions);
301 	return (((unsigned long long)m0 << 32) | m1);
302 }
303