xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/pack_float.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1988-1995, by Sun Microsystems, Inc.
24  */
25 
26 #pragma	ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "base_conversion.h"
29 
30 void
31 _fp_rightshift(pu, n)
32 	unpacked       *pu;
33 	int             n;
34 
35 /* Right shift significand sticky by n bits.  */
36 
37 {
38 	int             i;
39 
40 	if (n >= (32 * UNPACKED_SIZE)) {	/* drastic */
41 		for (i = 0; (pu->significand[i] == 0) && (i < UNPACKED_SIZE); i++);
42 		if (i >= UNPACKED_SIZE) {
43 			pu->fpclass = fp_zero;
44 			return;
45 		} else {
46 			for (i = 0; i < (UNPACKED_SIZE - 1); i++)
47 				pu->significand[i] = 0;
48 			pu->significand[UNPACKED_SIZE - 1] = 1;
49 			return;
50 		}
51 	}
52 	while (n >= 32) {	/* big shift */
53 		if (pu->significand[UNPACKED_SIZE - 1] != 0)
54 			pu->significand[UNPACKED_SIZE - 2] |= 1;
55 		for (i = UNPACKED_SIZE - 2; i >= 0; i--)
56 			pu->significand[i + 1] = pu->significand[i];
57 		pu->significand[0] = 0;
58 		n -= 32;
59 	}
60 	if (n >= 1) {		/* small shift */
61 		unsigned long   high, low, shiftout = 0;
62 		for (i = 0; i < UNPACKED_SIZE; i++) {
63 			high = pu->significand[i] >> n;
64 			low = pu->significand[i] << (32 - n);
65 			pu->significand[i] = shiftout | high;
66 			shiftout = low;
67 		}
68 		if (shiftout != 0)
69 			pu->significand[UNPACKED_SIZE - 1] |= 1;
70 	}
71 }
72 
73 PRIVATE int
74 overflow_to_infinity(sign)
75 	int             sign;
76 
77 /* Returns 1 if overflow should go to infinity, 0 if to max finite. */
78 
79 {
80 	int             inf;
81 
82 	switch (_fp_current_direction) {
83 	case fp_nearest:
84 		inf = 1;
85 		break;
86 	case fp_tozero:
87 		inf = 0;
88 		break;
89 	case fp_positive:
90 		inf = !sign;
91 		break;
92 	case fp_negative:
93 		inf = sign;
94 		break;
95 	}
96 	return (inf);
97 }
98 
99 PRIVATE void
100 round(pu, roundword)
101 	unpacked       *pu;
102 
103 /*
104  * Round according to current rounding mode. pu must be shifted to so that
105  * the roundbit is pu->significand[roundword] & 0x80000000
106  */
107 
108 {
109 	int             increment;	/* boolean to indicate round up */
110 	int             is;
111 	unsigned	msw;		/* msw before increment */
112 
113 	for (is = (roundword + 1); is < UNPACKED_SIZE; is++)
114 		if (pu->significand[is] != 0) {	/* Condense extra bits into
115 						 * sticky bottom of
116 						 * roundword. */
117 			pu->significand[roundword] |= 1;
118 			break;
119 		}
120 	if (pu->significand[roundword] == 0)
121 		return;
122 	_fp_set_exception(fp_inexact);
123 	switch (_fp_current_direction) {
124 	case fp_nearest:
125 		increment = pu->significand[roundword] >= 0x80000000;
126 		break;
127 	case fp_tozero:
128 		increment = 0;
129 		break;
130 	case fp_positive:
131 		increment = (pu->sign == 0) & (pu->significand[roundword] != 0);
132 		break;
133 	case fp_negative:
134 		increment = (pu->sign != 0) & (pu->significand[roundword] != 0);
135 		break;
136 	}
137 	if (increment) {
138 		msw=pu->significand[0];		/* save msw before round */
139 		is = roundword;
140 		do {
141 			is--;
142 			pu->significand[is]++;
143 		}
144 		while ((pu->significand[is] == 0) && (is > 0));
145 		if (pu->significand[0] < msw) {	/* rounding carried out */
146 			pu->exponent++;
147 			pu->significand[0] = 0x80000000;
148 		}
149 	}
150 	if ((_fp_current_direction == fp_nearest) && (pu->significand[roundword] == 0x80000000)) {	/* ambiguous case */
151 		pu->significand[roundword - 1] &= ~1;	/* force round to even */
152 	}
153 }
154 
155 void
156 _pack_single(pu, px)
157 	unpacked       *pu;	/* unpacked result */
158 	single         *px;	/* packed single */
159 {
160 	single_equivalence kluge;
161 
162 	kluge.f.msw.sign = pu->sign;
163 	switch (pu->fpclass) {
164 	case fp_zero:
165 		kluge.f.msw.exponent = 0;
166 		kluge.f.msw.significand = 0;
167 		break;
168 	case fp_infinity:
169 infinity:
170 		kluge.f.msw.exponent = 0xff;
171 		kluge.f.msw.significand = 0;
172 		break;
173 	case fp_quiet:
174 		kluge.f.msw.exponent = 0xff;
175 		kluge.f.msw.significand = 0x400000 | (0x3fffff & (pu->significand[0] >> 8));
176 		break;
177 	case fp_normal:
178 		_fp_rightshift(pu, 8);
179 		pu->exponent += SINGLE_BIAS;
180 		if (pu->exponent <= 0) {
181 			kluge.f.msw.exponent = 0;
182 			_fp_rightshift(pu, 1 - pu->exponent);
183 			round(pu, 1);
184 			if (pu->significand[0] == 0x800000) {	/* rounded back up to
185 								 * normal */
186 				kluge.f.msw.exponent = 1;
187 				kluge.f.msw.significand = 0;
188 				_fp_set_exception(fp_underflow);
189 				goto ret;
190 			}
191 			if (_fp_current_exceptions & (1 << fp_inexact))
192 				_fp_set_exception(fp_underflow);
193 			kluge.f.msw.significand = 0x7fffff & pu->significand[0];
194 			goto ret;
195 		}
196 		round(pu, 1);
197 		if (pu->significand[0] == 0x1000000) {	/* rounding overflow */
198 			pu->significand[0] = 0x800000;
199 			pu->exponent += 1;
200 		}
201 		if (pu->exponent >= 0xff) {
202 			_fp_set_exception(fp_overflow);
203 			_fp_set_exception(fp_inexact);
204 			if (overflow_to_infinity(pu->sign))
205 				goto infinity;
206 			kluge.f.msw.exponent = 0xfe;
207 			kluge.f.msw.significand = 0x7fffff;
208 			goto ret;
209 		}
210 		kluge.f.msw.exponent = pu->exponent;
211 		kluge.f.msw.significand = 0x7fffff & pu->significand[0];
212 	}
213 ret:
214 	*px = kluge.x;
215 }
216 
217 void
218 _pack_double(pu, px)
219 	unpacked       *pu;	/* unpacked result */
220 	double         *px;	/* packed double */
221 {
222 	double_equivalence kluge;
223 
224 	kluge.f.msw.sign = pu->sign;
225 	switch (pu->fpclass) {
226 	case fp_zero:
227 		kluge.f.msw.exponent = 0;
228 		kluge.f.msw.significand = 0;
229 		kluge.f.significand2 = 0;
230 		break;
231 	case fp_infinity:
232 infinity:
233 		kluge.f.msw.exponent = 0x7ff;
234 		kluge.f.msw.significand = 0;
235 		kluge.f.significand2 = 0;
236 		break;
237 	case fp_quiet:
238 		kluge.f.msw.exponent = 0x7ff;
239 		_fp_rightshift(pu, 11);
240 		kluge.f.msw.significand = 0x80000 | (0x7ffff & pu->significand[0]);
241 		kluge.f.significand2 = pu->significand[1];
242 		break;
243 	case fp_normal:
244 		_fp_rightshift(pu, 11);
245 		pu->exponent += DOUBLE_BIAS;
246 		if (pu->exponent <= 0) {	/* underflow */
247 			kluge.f.msw.exponent = 0;
248 			_fp_rightshift(pu, 1 - pu->exponent);
249 			round(pu, 2);
250 			if (pu->significand[0] == 0x100000) {	/* rounded back up to
251 								 * normal */
252 				kluge.f.msw.exponent = 1;
253 				kluge.f.msw.significand = 0;
254 				kluge.f.significand2 = 0;
255 				_fp_set_exception(fp_underflow);
256 				goto ret;
257 			}
258 			if (_fp_current_exceptions & (1 << fp_inexact))
259 				_fp_set_exception(fp_underflow);
260 			kluge.f.msw.exponent = 0;
261 			kluge.f.msw.significand = 0xfffff & pu->significand[0];
262 			kluge.f.significand2 = pu->significand[1];
263 			goto ret;
264 		}
265 		round(pu, 2);
266 		if (pu->significand[0] == 0x200000) {	/* rounding overflow */
267 			pu->significand[0] = 0x100000;
268 			pu->exponent += 1;
269 		}
270 		if (pu->exponent >= 0x7ff) {	/* overflow */
271 			_fp_set_exception(fp_overflow);
272 			_fp_set_exception(fp_inexact);
273 			if (overflow_to_infinity(pu->sign))
274 				goto infinity;
275 			kluge.f.msw.exponent = 0x7fe;
276 			kluge.f.msw.significand = 0xfffff;
277 			kluge.f.significand2 = 0xffffffff;
278 			goto ret;
279 		}
280 		kluge.f.msw.exponent = pu->exponent;
281 		kluge.f.msw.significand = 0xfffff & pu->significand[0];
282 		kluge.f.significand2 = pu->significand[1];
283 		break;
284 	}
285 ret:
286 	*px = kluge.x;
287 }
288 
289 void
290 _pack_extended(pu, px)
291 	unpacked       *pu;	/* unpacked result */
292 	extended       *px;	/* packed extended */
293 {
294 	extended_equivalence kluge;
295 
296 	kluge.f.msw.sign = pu->sign;
297 	switch (pu->fpclass) {
298 	case fp_zero:
299 		kluge.f.msw.exponent = 0;
300 		kluge.f.significand = 0;
301 		kluge.f.significand2 = 0;
302 		break;
303 	case fp_infinity:
304 infinity:
305 		kluge.f.msw.exponent = 0x7fff;
306 		kluge.f.significand = 0;
307 		kluge.f.significand2 = 0;
308 		break;
309 	case fp_quiet:
310 		kluge.f.msw.exponent = 0x7fff;
311 		kluge.f.significand = 0x40000000 | (0x7fffffff & pu->significand[0]);
312 		kluge.f.significand2 = pu->significand[1];
313 		break;
314 	case fp_normal:
315 		switch (_fp_current_precision) {
316 		case fp_single:
317 			{
318 				single          s;
319 				_pack_single(pu, &s);
320 				_unpack_single(pu, &s);
321 				break;
322 			}
323 		case fp_double:
324 			{
325 				double          s;
326 				_pack_double(pu, &s);
327 				_unpack_double(pu, &s);
328 				break;
329 			}
330 		}
331 		pu->exponent += EXTENDED_BIAS;
332 		if (pu->exponent <= 0) {	/* underflow */
333 			kluge.f.msw.exponent = 0;
334 			_fp_rightshift(pu, -pu->exponent);
335 			round(pu, 2);
336 			if (_fp_current_exceptions & (1 << fp_inexact))
337 				_fp_set_exception(fp_underflow);
338 			kluge.f.msw.exponent = 0;
339 			kluge.f.significand = pu->significand[0];
340 			kluge.f.significand2 = pu->significand[1];
341 			goto ret;
342 		}
343 		round(pu, 2);
344 		if (pu->exponent >= 0x7fff) {	/* overflow */
345 			_fp_set_exception(fp_overflow);
346 			_fp_set_exception(fp_inexact);
347 			if (overflow_to_infinity(pu->sign))
348 				goto infinity;
349 			kluge.f.msw.exponent = 0x7ffe;
350 			kluge.f.significand = 0xffffffff;
351 			kluge.f.significand2 = 0xffffffff;
352 			goto ret;
353 		}
354 		kluge.f.msw.exponent = pu->exponent;
355 		kluge.f.significand = pu->significand[0];
356 		kluge.f.significand2 = pu->significand[1];
357 		break;
358 	}
359 ret:
360 	(*px)[0] = kluge.x[0];
361 	(*px)[1] = kluge.x[1];
362 	(*px)[2] = kluge.x[2];
363 }
364 
365 void
366 _pack_quadruple(pu, px)
367 	unpacked       *pu;	/* unpacked result */
368 	quadruple      *px;	/* packed quadruple */
369 {
370 	quadruple_equivalence kluge;
371 	int             i;
372 
373 	kluge.f.msw.sign = pu->sign;
374 	switch (pu->fpclass) {
375 	case fp_zero:
376 		kluge.f.msw.exponent = 0;
377 		kluge.f.msw.significand = 0;
378 		kluge.f.significand2 = 0;
379 		kluge.f.significand3 = 0;
380 		kluge.f.significand4 = 0;
381 		break;
382 	case fp_infinity:
383 infinity:
384 		kluge.f.msw.exponent = 0x7fff;
385 		kluge.f.msw.significand = 0;
386 		kluge.f.significand2 = 0;
387 		kluge.f.significand3 = 0;
388 		kluge.f.significand4 = 0;
389 		break;
390 	case fp_quiet:
391 		kluge.f.msw.exponent = 0x7fff;
392 		_fp_rightshift(pu, 15);
393 		kluge.f.msw.significand = 0x8000 | (0xffff & pu->significand[0]);
394 		kluge.f.significand2 = pu->significand[1];
395 		kluge.f.significand3 = pu->significand[2];
396 		kluge.f.significand4 = pu->significand[3];
397 		break;
398 	case fp_normal:
399 		_fp_rightshift(pu, 15);
400 		pu->exponent += QUAD_BIAS;
401 		if (pu->exponent <= 0) {	/* underflow */
402 			kluge.f.msw.exponent = 0;
403 			_fp_rightshift(pu, 1 - pu->exponent);
404 			round(pu, 4);
405 			if (pu->significand[0] == 0x10000) {	/* rounded back up to
406 								 * normal */
407 				kluge.f.msw.exponent = 1;
408 				kluge.f.msw.significand = 0;
409 				kluge.f.significand2 = 0;
410 				kluge.f.significand3 = 0;
411 				kluge.f.significand4 = 0;
412 				_fp_set_exception(fp_underflow);
413 				goto ret;
414 			}
415 			if (_fp_current_exceptions & (1 << fp_inexact))
416 				_fp_set_exception(fp_underflow);
417 			kluge.f.msw.exponent = 0;
418 			kluge.f.msw.significand = 0xffff & pu->significand[0];
419 			kluge.f.significand2 = pu->significand[1];
420 			kluge.f.significand3 = pu->significand[2];
421 			kluge.f.significand4 = pu->significand[3];
422 			goto ret;
423 		}
424 		round(pu, 4);
425 		if (pu->significand[0] == 0x20000) {	/* rounding overflow */
426 			pu->significand[0] = 0x10000;
427 			pu->exponent += 1;
428 		}
429 		if (pu->exponent >= 0x7fff) {	/* overflow */
430 			_fp_set_exception(fp_overflow);
431 			_fp_set_exception(fp_inexact);
432 			if (overflow_to_infinity(pu->sign))
433 				goto infinity;
434 			kluge.f.msw.exponent = 0x7ffe;
435 			kluge.f.msw.significand = 0xffff;
436 			kluge.f.significand2 = 0xffffffff;
437 			kluge.f.significand3 = 0xffffffff;
438 			kluge.f.significand4 = 0xffffffff;
439 			goto ret;
440 		}
441 		kluge.f.msw.exponent = pu->exponent;
442 		kluge.f.msw.significand = pu->significand[0] & 0xffff;
443 		kluge.f.significand2 = pu->significand[1];
444 		kluge.f.significand3 = pu->significand[2];
445 		kluge.f.significand4 = pu->significand[3];
446 		break;
447 	}
448 ret:
449 #ifdef __STDC__
450 	*px = kluge.x;
451 #else
452 	for (i = 0; i < 4; i++)
453 		px->u[i] = kluge.x.u[i];
454 #endif
455 }
456