xref: /onnv-gate/usr/src/lib/libbc/libc/gen/common/double_decim.c (revision 722:636b850d4ee9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*722Smuffin /*
23*722Smuffin  * Copyright 1988 Sun Microsystems, Inc.  All rights reserved.
24*722Smuffin  * Use is subject to license terms.
25*722Smuffin  */
260Sstevel@tonic-gate 
27*722Smuffin #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /* Conversion between binary and decimal floating point. */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include "base_conversion.h"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /* PRIVATE FUNCTIONS */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate /*
360Sstevel@tonic-gate  * Rounds decimal record *pd according to modes in *pm, recording exceptions
370Sstevel@tonic-gate  * for inexact or overflow in *ps.  round is the round digit and sticky is 0
380Sstevel@tonic-gate  * or non-zero to indicate exact or inexact. pd->ndigits is expected to be
390Sstevel@tonic-gate  * correctly set.
400Sstevel@tonic-gate  */
41*722Smuffin void
decimal_round(decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps,char round,unsigned sticky)42*722Smuffin decimal_round(decimal_mode *pm, decimal_record *pd, fp_exception_field_type *ps,
43*722Smuffin     char round, unsigned sticky)
440Sstevel@tonic-gate {
450Sstevel@tonic-gate 	int             lsd, i;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate 	if ((round == '0') && (sticky == 0)) {	/* Exact. */
480Sstevel@tonic-gate 		goto done;
490Sstevel@tonic-gate 	}
500Sstevel@tonic-gate 	*ps |= 1 << fp_inexact;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	switch (pm->rd) {
530Sstevel@tonic-gate 	case fp_nearest:
540Sstevel@tonic-gate 		if (round < '5')
550Sstevel@tonic-gate 			goto done;
560Sstevel@tonic-gate 		if (round > '5')
570Sstevel@tonic-gate 			goto roundup;
580Sstevel@tonic-gate 		if (sticky != 0)
590Sstevel@tonic-gate 			goto roundup;
600Sstevel@tonic-gate 		/* Now in ambiguous case; round up if lsd is odd. */
610Sstevel@tonic-gate 		if (pd->ndigits <= 0)
620Sstevel@tonic-gate 			goto done;	/* Presumed 0. */
630Sstevel@tonic-gate 		lsd = pd->ds[pd->ndigits - 1] - '0';
640Sstevel@tonic-gate 		if ((lsd % 2) == 0)
650Sstevel@tonic-gate 			goto done;
660Sstevel@tonic-gate 		goto roundup;
670Sstevel@tonic-gate 	case fp_positive:
680Sstevel@tonic-gate 		if (pd->sign != 0)
690Sstevel@tonic-gate 			goto done;
700Sstevel@tonic-gate 		goto roundup;
710Sstevel@tonic-gate 	case fp_negative:
720Sstevel@tonic-gate 		if (pd->sign == 0)
730Sstevel@tonic-gate 			goto done;
740Sstevel@tonic-gate 		goto roundup;
750Sstevel@tonic-gate 	case fp_tozero:
760Sstevel@tonic-gate 		goto done;
770Sstevel@tonic-gate 	}
780Sstevel@tonic-gate roundup:
790Sstevel@tonic-gate 	for (i = (pd->ndigits - 1); (pd->ds[i] == '9') && (i >= 0); i--)
800Sstevel@tonic-gate 		pd->ds[i] = '0';
810Sstevel@tonic-gate 	if (i >= 0)
820Sstevel@tonic-gate 		(pd->ds[i])++;
830Sstevel@tonic-gate 	else {			/* Rounding carry out has occurred. */
840Sstevel@tonic-gate 		pd->ds[0] = '1';
850Sstevel@tonic-gate 		if (pm->df == floating_form) {	/* For E format, simply
860Sstevel@tonic-gate 						 * adjust exponent. */
870Sstevel@tonic-gate 			pd->exponent++;
880Sstevel@tonic-gate 		} else {	/* For F format, increase length of string. */
890Sstevel@tonic-gate 			if (pd->ndigits > 0)
900Sstevel@tonic-gate 				pd->ds[pd->ndigits] = '0';
910Sstevel@tonic-gate 			pd->ndigits++;
920Sstevel@tonic-gate 		}
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 	goto ret;
950Sstevel@tonic-gate done:
960Sstevel@tonic-gate 	if (pd->ndigits <= 0) {	/* Create zero string. */
970Sstevel@tonic-gate 		pd->ds[0] = '0';
980Sstevel@tonic-gate 		pd->ndigits = 1;
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate ret:
1010Sstevel@tonic-gate 	pd->ds[pd->ndigits] = 0;/* Terminate string. */
1020Sstevel@tonic-gate 	return;
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * Converts an unpacked integer value *pu into a decimal string in *ds, of
107*722Smuffin  * length returned in *ndigs. Inexactness is indicated by setting
1080Sstevel@tonic-gate  * ds[ndigs-1] odd.
109*722Smuffin  *
110*722Smuffin  * Arguments
111*722Smuffin  *	pu:		Input unpacked integer value input.
112*722Smuffin  *	nsig:		Input number of significant digits required.
113*722Smuffin  *	ds:		Output decimal integer string output
114*722Smuffin  *			must be large enough.
115*722Smuffin  *	nzeros:		Output number of implicit trailing zeros
116*722Smuffin  *			produced.
117*722Smuffin  *	ndigs:		Output number of explicit digits produced
118*722Smuffin  *			in ds.
1190Sstevel@tonic-gate  */
120*722Smuffin void
binary_to_decimal_integer(unpacked * pu,unsigned nsig,char ds[],unsigned * nzeros,unsigned * ndigs)121*722Smuffin binary_to_decimal_integer(unpacked *pu, unsigned nsig, char ds[],
122*722Smuffin     unsigned *nzeros, unsigned *ndigs)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	_big_float     *pd, b, d;
1260Sstevel@tonic-gate 	int             e, i, is;
1270Sstevel@tonic-gate 	_BIG_FLOAT_DIGIT stickyshift;
1280Sstevel@tonic-gate 	char            s[4];
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	b.bsize = _BIG_FLOAT_SIZE;	/* Initialize sizes of big floats. */
1310Sstevel@tonic-gate 	d.bsize = _BIG_FLOAT_SIZE;
1320Sstevel@tonic-gate 	_unpacked_to_big_float(pu, &b, &e);
1330Sstevel@tonic-gate 	if (e < 0) {
1340Sstevel@tonic-gate 		_right_shift_base_two(&b, (short unsigned) -e, &stickyshift);
1350Sstevel@tonic-gate #ifdef DEBUG
1360Sstevel@tonic-gate 		assert(stickyshift == 0);
1370Sstevel@tonic-gate #endif
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 	_big_binary_to_big_decimal(&b, &d);
1400Sstevel@tonic-gate 	if (e <= 0)
1410Sstevel@tonic-gate 		pd = &d;
1420Sstevel@tonic-gate 	else {
1430Sstevel@tonic-gate 		_big_float_times_power(&d, 2, e, (int) nsig, &pd);
1440Sstevel@tonic-gate 		switch ((unsigned int)pd) {
1450Sstevel@tonic-gate 		case ((unsigned int)BIG_FLOAT_TIMES_TOOBIG):
1460Sstevel@tonic-gate 			{
1470Sstevel@tonic-gate 				char            bcastring[80];
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 				(void) sprintf(bcastring, " binary exponent %d ", e);
1500Sstevel@tonic-gate 				_base_conversion_abort(ERANGE, bcastring);
1510Sstevel@tonic-gate 				break;
1520Sstevel@tonic-gate 			}
1530Sstevel@tonic-gate 		case ((unsigned int)BIG_FLOAT_TIMES_NOMEM):
1540Sstevel@tonic-gate 			{
1550Sstevel@tonic-gate 				char            bcastring[80];
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 				(void) sprintf(bcastring, " binary exponent %d ", e);
1580Sstevel@tonic-gate 				_base_conversion_abort(ENOMEM, bcastring);
1590Sstevel@tonic-gate 				break;
1600Sstevel@tonic-gate 			}
1610Sstevel@tonic-gate 		default:
1620Sstevel@tonic-gate #ifdef DEBUG
1630Sstevel@tonic-gate 			if (pd != &d)
1640Sstevel@tonic-gate 				(void) printf(" large binary exponent %d needs heap buffer \n", e);
1650Sstevel@tonic-gate 			printf(" product ");
1660Sstevel@tonic-gate 			_display_big_float(pd, 10);
1670Sstevel@tonic-gate #endif
1680Sstevel@tonic-gate 			break;
1690Sstevel@tonic-gate 		}
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 	_fourdigitsquick((short unsigned) pd->bsignificand[pd->blength - 1], s);
1720Sstevel@tonic-gate 	for (i = 0; s[i] == '0'; i++);	/* Find first non-zero digit. */
1730Sstevel@tonic-gate 	for (is = 0; i <= 3;)
1740Sstevel@tonic-gate 		ds[is++] = s[i++];	/* Copy subsequent digits. */
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	for (i = (pd->blength - 2); i >= 0; i--) {	/* Convert powers of
1770Sstevel@tonic-gate 							 * 10**4 to decimal
1780Sstevel@tonic-gate 							 * digits. */
1790Sstevel@tonic-gate 		_fourdigitsquick((short unsigned) pd->bsignificand[i], &(ds[is]));
1800Sstevel@tonic-gate 		is += 4;
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	ds[is] = 0;
1840Sstevel@tonic-gate 	*ndigs = is;
1850Sstevel@tonic-gate 	*nzeros = pd->bexponent;
1860Sstevel@tonic-gate 	if (pd != &d)
1870Sstevel@tonic-gate 		_free_big_float(pd);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate #ifdef DEBUG
1900Sstevel@tonic-gate 	printf(" binary to decimal integer result %s * 10**%d \n", ds, *nzeros);
1910Sstevel@tonic-gate #endif
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate /*
1950Sstevel@tonic-gate  * Converts an unpacked fraction value *pu into a decimal string consisting
1960Sstevel@tonic-gate  * of a) an implicit '.' b) *nzeros implicit leading zeros c) *ndigs explicit
1970Sstevel@tonic-gate  * digits in ds ds contains at least nsig significant digits. nzeros + *
1980Sstevel@tonic-gate  * *ndigs is at least nfrac digits after the point. Inexactness is indicated
1990Sstevel@tonic-gate  * by sticking to the lsb.
200*722Smuffin  *
201*722Smuffin  * Arguments
202*722Smuffin  *
203*722Smuffin  *	pu:		Input unpacked fraction value output < 1
204*722Smuffin  *			in magnitude.
205*722Smuffin  *	nsig:		Input number of significant digits
206*722Smuffin  *			required.
207*722Smuffin  *	nfrac:		Input number of digits after point
208*722Smuffin  *			required.
209*722Smuffin  *	ds:		Output decimal integer string output -
210*722Smuffin  *			must be large enough.
211*722Smuffin  *	nzeros:		Output number of implicit leading zeros
212*722Smuffin  *			produced.
213*722Smuffin  *	ndigs:		Output number of explicit digits produced
214*722Smuffin  *			in ds.
2150Sstevel@tonic-gate  */
216*722Smuffin  void
binary_to_decimal_fraction(unpacked * pu,unsigned nsig,unsigned nfrac,char ds[],int * nzeros,int * ndigs)217*722Smuffin binary_to_decimal_fraction(unpacked *pu, unsigned nsig, unsigned nfrac,
218*722Smuffin     char ds[], int *nzeros, int *ndigs)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	_big_float     *pb, b, d;
2210Sstevel@tonic-gate 	int             e, i, j, is, excess;
2220Sstevel@tonic-gate 	char            s[4];
2230Sstevel@tonic-gate 	int             tensig, tenpower;
2240Sstevel@tonic-gate 	_BIG_FLOAT_DIGIT stickyshift;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	*nzeros = 0;
2270Sstevel@tonic-gate 	if (pu->fpclass == fp_zero) {	/* Exact zero. */
2280Sstevel@tonic-gate 		for (i = 0; i <= nfrac; i++)
2290Sstevel@tonic-gate 			ds[i] = '0';
2300Sstevel@tonic-gate 		for (; i <= nsig; i++)
2310Sstevel@tonic-gate 			ds[i] = '0';
2320Sstevel@tonic-gate 		*ndigs = i;
2330Sstevel@tonic-gate 		return;
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate 	b.bsize = _BIG_FLOAT_SIZE;	/* Initialize sizes of big floats. */
2360Sstevel@tonic-gate 	d.bsize = _BIG_FLOAT_SIZE;
2370Sstevel@tonic-gate 	_unpacked_to_big_float(pu, &b, &e);
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * e < 0 always
2400Sstevel@tonic-gate 	 */
2410Sstevel@tonic-gate 	b.bexponent = e;
2420Sstevel@tonic-gate 	tenpower = nsig + (int) (((17 - e - 16 * b.blength) * (unsigned long) 19729) >> 16);
2430Sstevel@tonic-gate 	if (tenpower < nfrac)
2440Sstevel@tonic-gate 		tenpower = nfrac;
2450Sstevel@tonic-gate 	tensig = nfrac;
2460Sstevel@tonic-gate 	if (nsig > tensig)
2470Sstevel@tonic-gate 		tensig = nsig;
2480Sstevel@tonic-gate 	tensig = 1 + (((tensig + 2) * 217706) >> 16);
2490Sstevel@tonic-gate 	tensig = -tensig;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate #ifdef DEBUG
2520Sstevel@tonic-gate 	printf(" binary to decimal fraction exponent 2**%d \n", e);
2530Sstevel@tonic-gate 	printf(" binary to decimal fraction nsig %d nfrac %d tenpower %d tensig %d \n", nsig, nfrac, tenpower, tensig);
2540Sstevel@tonic-gate #endif
2550Sstevel@tonic-gate 	_big_float_times_power(&b, 10, tenpower, tensig, &pb);
2560Sstevel@tonic-gate 	switch ((unsigned int)pb) {
2570Sstevel@tonic-gate 	case ((unsigned int)BIG_FLOAT_TIMES_TOOBIG):
2580Sstevel@tonic-gate 		{
2590Sstevel@tonic-gate 			char            bcastring[80];
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 			(void) sprintf(bcastring, " decimal exponent %d ", tenpower);
2620Sstevel@tonic-gate 			_base_conversion_abort(ERANGE, bcastring);
2630Sstevel@tonic-gate 			break;
2640Sstevel@tonic-gate 		}
2650Sstevel@tonic-gate 	case ((unsigned int)BIG_FLOAT_TIMES_NOMEM):
2660Sstevel@tonic-gate 		{
2670Sstevel@tonic-gate 			char            bcastring[80];
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 			(void) sprintf(bcastring, " decimal exponent %d ", tenpower);
2700Sstevel@tonic-gate 			_base_conversion_abort(ENOMEM, bcastring);
2710Sstevel@tonic-gate 			break;
2720Sstevel@tonic-gate 		}
2730Sstevel@tonic-gate 	default:
2740Sstevel@tonic-gate #ifdef DEBUG
2750Sstevel@tonic-gate 		if (pb != &b)
2760Sstevel@tonic-gate 			printf(" large decimal exponent %d needs heap buffer \n", tenpower);
2770Sstevel@tonic-gate 		printf(" product ");
2780Sstevel@tonic-gate 		_display_big_float(pb, 2);
2790Sstevel@tonic-gate #endif
2800Sstevel@tonic-gate 		break;
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	if (pb->bexponent <= -16) {
2840Sstevel@tonic-gate 		/* Have computed appropriate decimal part; now toss fraction. */
2850Sstevel@tonic-gate 		excess = (-pb->bexponent) / 16;
2860Sstevel@tonic-gate #ifdef DEBUG
2870Sstevel@tonic-gate 		printf(" discard %d excess fraction bits \n", 16 * excess);
2880Sstevel@tonic-gate #endif
2890Sstevel@tonic-gate 		for (i = 0; (i < excess) && (pb->bsignificand[i] == 0); i++);
2900Sstevel@tonic-gate 		if (i < excess)
2910Sstevel@tonic-gate 			pb->bsignificand[excess] |= 1;	/* Sticky bit for
2920Sstevel@tonic-gate 							 * discarded fraction. */
2930Sstevel@tonic-gate 		for (i = excess; i < pb->blength; i++)
2940Sstevel@tonic-gate 			pb->bsignificand[i - excess] = pb->bsignificand[i];
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 		pb->blength -= excess;
2970Sstevel@tonic-gate 		pb->bexponent += 16 * excess;
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	if (pb->bexponent < 0) {
3000Sstevel@tonic-gate 		_right_shift_base_two(pb, (short unsigned) -pb->bexponent, &stickyshift);
3010Sstevel@tonic-gate 		if (stickyshift != 0)
3020Sstevel@tonic-gate 			pb->bsignificand[0] |= 1;	/* Stick to lsb. */
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	_big_binary_to_big_decimal(pb, &d);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	i = d.blength - 1;
3070Sstevel@tonic-gate 	while (d.bsignificand[i] == 0)
3080Sstevel@tonic-gate 		i--;
3090Sstevel@tonic-gate 	_fourdigitsquick((short unsigned) d.bsignificand[i], s);
3100Sstevel@tonic-gate 	for (j = 0; s[j] == '0'; j++);	/* Find first non-zero digit. */
3110Sstevel@tonic-gate 	for (is = 0; j <= 3;)
3120Sstevel@tonic-gate 		ds[is++] = s[j++];	/* Copy subsequent digits. */
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	for (i--; i >= 0; i--) {/* Convert powers of 10**4 to decimal digits. */
3150Sstevel@tonic-gate 		_fourdigitsquick((short unsigned) d.bsignificand[i], &(ds[is]));
3160Sstevel@tonic-gate 		is += 4;
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	ds[is] = 0;
3200Sstevel@tonic-gate 	*ndigs = is;
3210Sstevel@tonic-gate #ifdef DEBUG
3220Sstevel@tonic-gate 	assert(tenpower >= is);
3230Sstevel@tonic-gate #endif
3240Sstevel@tonic-gate 	*nzeros = tenpower - is;/* There were supposed to be tenpower leading
3250Sstevel@tonic-gate 				 * digits, and is were found. */
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (pb != &b)
3280Sstevel@tonic-gate 		_free_big_float(pb);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate #ifdef DEBUG
3310Sstevel@tonic-gate 	printf(" binary to decimal fraction result .%s * 10**%d \n", ds, -(*nzeros));
3320Sstevel@tonic-gate #endif
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate void
_unpacked_to_decimal(unpacked * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)337*722Smuffin _unpacked_to_decimal(unpacked *px, decimal_mode *pm, decimal_record *pd,
338*722Smuffin     fp_exception_field_type *ps)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	unpacked        fx, ix;
3410Sstevel@tonic-gate 	unsigned        fmask, imask;
3420Sstevel@tonic-gate 	int             i, intdigs, fracdigs, fraczeros, fracsigs, ids, idsbound, lzbound;
3430Sstevel@tonic-gate 	unsigned        nsig, nfrac, intzeros, intsigs;
3440Sstevel@tonic-gate 	char            is[_INTEGER_SIZE], fs[DECIMAL_STRING_LENGTH];
3450Sstevel@tonic-gate 	char            round = '0';
3460Sstevel@tonic-gate 	unsigned        sticky = 0;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	pd->sign = px->sign;
3490Sstevel@tonic-gate 	pd->fpclass = px->fpclass;
3500Sstevel@tonic-gate 	if ((px->fpclass != fp_normal) && (px->fpclass != fp_subnormal))
3510Sstevel@tonic-gate 		return;
3520Sstevel@tonic-gate 	if ((pm->ndigits >= DECIMAL_STRING_LENGTH) ||
3530Sstevel@tonic-gate 	    ((pm->df == floating_form) && (pm->ndigits < 1))) {	/* Gross overflow or bad
3540Sstevel@tonic-gate 								 * spec. */
3550Sstevel@tonic-gate overflow:
3560Sstevel@tonic-gate 		*ps |= 1 << fp_overflow;
3570Sstevel@tonic-gate 		return;
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 	/* Divide x up into integer part ix and fraction part fx.	 */
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	ix = *px;
3620Sstevel@tonic-gate 	fx = ix;
3630Sstevel@tonic-gate 	if (ix.exponent <= -1) {/* All fraction. */
3640Sstevel@tonic-gate 		ix.fpclass = fp_zero;
3650Sstevel@tonic-gate 	} else if (ix.exponent >= 159) {	/* All integer. */
3660Sstevel@tonic-gate 		fx.fpclass = fp_zero;
3670Sstevel@tonic-gate 	} else if ((ix.exponent % 32) == 31) {	/* Integer/fraction boundary
3680Sstevel@tonic-gate 						 * is conveniently on a word
3690Sstevel@tonic-gate 						 * boundary. */
3700Sstevel@tonic-gate 		imask = (ix.exponent + 1) / 32;	/* Words 0..imask-1 are
3710Sstevel@tonic-gate 						 * integer; imask..SIZE are
3720Sstevel@tonic-gate 						 * fraction. */
3730Sstevel@tonic-gate 		for (i = 0; i < imask; i++)
3740Sstevel@tonic-gate 			fx.significand[i] = 0;
3750Sstevel@tonic-gate 		for (; i < UNPACKED_SIZE; i++)
3760Sstevel@tonic-gate 			ix.significand[i] = 0;
3770Sstevel@tonic-gate 		_fp_normalize(&fx);
3780Sstevel@tonic-gate 	} else {		/* Integer/fraction boundary falls in the
3790Sstevel@tonic-gate 				 * middle of a word. */
3800Sstevel@tonic-gate 		imask = (ix.exponent + 1) / 32;	/* Words 0..imask-1 are
3810Sstevel@tonic-gate 						 * integer; imask is integer
3820Sstevel@tonic-gate 						 * and fraction ;
3830Sstevel@tonic-gate 						 * imask+1..SIZE are
3840Sstevel@tonic-gate 						 * fraction. */
3850Sstevel@tonic-gate 		for (i = 0; i < imask; i++)
3860Sstevel@tonic-gate 			fx.significand[i] = 0;
3870Sstevel@tonic-gate 		fmask = (1 << (31 - (ix.exponent % 32))) - 1;
3880Sstevel@tonic-gate 		fx.significand[imask] &= fmask;
3890Sstevel@tonic-gate 		ix.significand[imask] &= ~fmask;
3900Sstevel@tonic-gate 		for (i = (imask + 1); i < UNPACKED_SIZE; i++)
3910Sstevel@tonic-gate 			ix.significand[i] = 0;
3920Sstevel@tonic-gate 		_fp_normalize(&fx);
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 	if (ix.fpclass != fp_zero) {	/* Compute integer part of result. */
3950Sstevel@tonic-gate 		if (pm->df == floating_form)
3960Sstevel@tonic-gate 			nsig = pm->ndigits + 1;	/* Significant digits wanted
3970Sstevel@tonic-gate 						 * for E format, plus one for
3980Sstevel@tonic-gate 						 * rounding. */
3990Sstevel@tonic-gate 		else
4000Sstevel@tonic-gate 			nsig = _INTEGER_SIZE;	/* Significant digits wanted
4010Sstevel@tonic-gate 						 * for F format == all. */
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		binary_to_decimal_integer(&ix, nsig, is, &intzeros, &intsigs);
4040Sstevel@tonic-gate 	} else {
4050Sstevel@tonic-gate 		intsigs = 0;
4060Sstevel@tonic-gate 		intzeros = 0;
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 	intdigs = intsigs + intzeros;
4090Sstevel@tonic-gate 	fracdigs = 0;
4100Sstevel@tonic-gate 	if (((pm->df == fixed_form) && (pm->ndigits >= 0)) ||
4110Sstevel@tonic-gate 	    ((pm->df == floating_form) && ((pm->ndigits + 1) > intdigs))) {	/* Need to compute
4120Sstevel@tonic-gate 										 * fraction part. */
4130Sstevel@tonic-gate 		if (pm->df == floating_form) {	/* Need more significant
4140Sstevel@tonic-gate 						 * digits. */
4150Sstevel@tonic-gate 			nsig = pm->ndigits + 2 - intdigs;	/* Add two for rounding,
4160Sstevel@tonic-gate 								 * sticky. */
4170Sstevel@tonic-gate 			if (nsig > DECIMAL_STRING_LENGTH)
4180Sstevel@tonic-gate 				nsig = DECIMAL_STRING_LENGTH;
4190Sstevel@tonic-gate 			nfrac = 1;
4200Sstevel@tonic-gate 		} else {	/* Need fraction digits. */
4210Sstevel@tonic-gate 			nsig = 0;
4220Sstevel@tonic-gate 			nfrac = pm->ndigits + 2;	/* Add two for rounding,
4230Sstevel@tonic-gate 							 * sticky. */
4240Sstevel@tonic-gate 			if (nfrac > DECIMAL_STRING_LENGTH)
4250Sstevel@tonic-gate 				nfrac = DECIMAL_STRING_LENGTH;
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 		binary_to_decimal_fraction(&fx, nsig, nfrac, fs, &fraczeros, &fracsigs);
4280Sstevel@tonic-gate 		fracdigs = fraczeros + fracsigs;
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate 	if (pm->df == floating_form) {	/* Combine integer and fraction for E
4310Sstevel@tonic-gate 					 * format. */
4320Sstevel@tonic-gate 		idsbound = intsigs;
4330Sstevel@tonic-gate 		if (idsbound > pm->ndigits)
4340Sstevel@tonic-gate 			idsbound = pm->ndigits;
4350Sstevel@tonic-gate 		for (ids = 0; ids < idsbound; ids++)
4360Sstevel@tonic-gate 			pd->ds[ids] = is[ids];
4370Sstevel@tonic-gate 		/* Put integer into output string. */
4380Sstevel@tonic-gate 		idsbound = intsigs + intzeros;
4390Sstevel@tonic-gate 		if (idsbound > pm->ndigits)
4400Sstevel@tonic-gate 			idsbound = pm->ndigits;
4410Sstevel@tonic-gate 		for (; ids < idsbound; ids++)
4420Sstevel@tonic-gate 			pd->ds[ids] = '0';
4430Sstevel@tonic-gate 		if (ids == pm->ndigits) {	/* Integer part had enough
4440Sstevel@tonic-gate 						 * significant digits. */
4450Sstevel@tonic-gate 			pd->ndigits = ids;
4460Sstevel@tonic-gate 			pd->exponent = intdigs - ids;
4470Sstevel@tonic-gate 			if (ids < intdigs) {	/* Gather rounding info. */
4480Sstevel@tonic-gate 				if (ids < intsigs)
4490Sstevel@tonic-gate 					round = is[ids++];
4500Sstevel@tonic-gate 				else
4510Sstevel@tonic-gate 					round = '0';
4520Sstevel@tonic-gate 				for (; (is[ids] == '0') && (ids < intsigs); ids++);
4530Sstevel@tonic-gate 				if (ids < intsigs)
4540Sstevel@tonic-gate 					sticky = 1;
4550Sstevel@tonic-gate 				if (fx.fpclass != fp_zero)
4560Sstevel@tonic-gate 					sticky = 1;
4570Sstevel@tonic-gate 			} else {/* Integer part is exact - round from
4580Sstevel@tonic-gate 				 * fraction. */
4590Sstevel@tonic-gate 				if (fx.fpclass != fp_zero) {
4600Sstevel@tonic-gate 					int             stickystart;
4610Sstevel@tonic-gate 					/* Fraction non-zero. */
4620Sstevel@tonic-gate 					if (fraczeros > 0) {	/* Round digit is zero. */
4630Sstevel@tonic-gate 						round = '0';
4640Sstevel@tonic-gate 						stickystart = 0;	/* Stickies start with
4650Sstevel@tonic-gate 									 * fs[0]. */
4660Sstevel@tonic-gate 					} else {	/* Round digit is fs[0]. */
4670Sstevel@tonic-gate 						round = fs[0];
4680Sstevel@tonic-gate 						stickystart = 1;	/* Stickies start with
4690Sstevel@tonic-gate 									 * fs[1]. */
4700Sstevel@tonic-gate 					}
4710Sstevel@tonic-gate 					if (sticky == 0) {	/* Search for sticky
4720Sstevel@tonic-gate 								 * bits. */
4730Sstevel@tonic-gate 						for (ids = stickystart; (fs[ids] == '0') && (ids < fracdigs); ids++);
4740Sstevel@tonic-gate 						if (ids < fracdigs)
4750Sstevel@tonic-gate 							sticky = 1;
4760Sstevel@tonic-gate 					}
4770Sstevel@tonic-gate 				}
4780Sstevel@tonic-gate 			}
4790Sstevel@tonic-gate 		} else {	/* Need more significant digits from fraction
4800Sstevel@tonic-gate 				 * part. */
4810Sstevel@tonic-gate 			idsbound = pm->ndigits - ids;
4820Sstevel@tonic-gate 			if (ids == 0) {	/* No integer part - find first
4830Sstevel@tonic-gate 					 * significant digit. */
4840Sstevel@tonic-gate 				for (i = 0; fs[i] == '0'; i++);
4850Sstevel@tonic-gate 				idsbound = i + idsbound + fraczeros;
4860Sstevel@tonic-gate 				i += fraczeros;	/* Point i at first
4870Sstevel@tonic-gate 						 * significant digit. */
4880Sstevel@tonic-gate 			} else
4890Sstevel@tonic-gate 				i = 0;
4900Sstevel@tonic-gate 			if (idsbound > fracdigs)
4910Sstevel@tonic-gate 				idsbound = fracdigs;
4920Sstevel@tonic-gate 			pd->exponent = -idsbound;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 			if (fraczeros < idsbound)	/* Compute number of
4950Sstevel@tonic-gate 							 * leading zeros
4960Sstevel@tonic-gate 							 * required. */
4970Sstevel@tonic-gate 				lzbound = fraczeros;
4980Sstevel@tonic-gate 			else
4990Sstevel@tonic-gate 				lzbound = idsbound;
5000Sstevel@tonic-gate 			for (; (i < lzbound); i++)
5010Sstevel@tonic-gate 				pd->ds[ids++] = '0';
5020Sstevel@tonic-gate 			for (; (i < idsbound); i++)
5030Sstevel@tonic-gate 				pd->ds[ids++] = fs[i - fraczeros];
5040Sstevel@tonic-gate 			i -= fraczeros;	/* Don't worry about leading zeros
5050Sstevel@tonic-gate 					 * from now on, we're just rounding */
5060Sstevel@tonic-gate 			if (i < fracsigs) {	/* Gather rounding info.  */
5070Sstevel@tonic-gate 				if (i < 0)
5080Sstevel@tonic-gate 					round = '0';
5090Sstevel@tonic-gate 				else
5100Sstevel@tonic-gate 					round = fs[i];
5110Sstevel@tonic-gate 				i++;
5120Sstevel@tonic-gate 				if (sticky == 0) {	/* Find out if remainder
5130Sstevel@tonic-gate 							 * is exact. */
5140Sstevel@tonic-gate 					if (i < 0)
5150Sstevel@tonic-gate 						i = 0;
5160Sstevel@tonic-gate 					for (; (fs[i] == '0') && (i < fracsigs); i++);
5170Sstevel@tonic-gate 					if (i < fracsigs)
5180Sstevel@tonic-gate 						sticky = 1;
5190Sstevel@tonic-gate 				}
5200Sstevel@tonic-gate 			} else {/* Fraction part is exact - add zero digits
5210Sstevel@tonic-gate 				 * if required. */
5220Sstevel@tonic-gate 				for (; ids < pm->ndigits; ids++)
5230Sstevel@tonic-gate 					pd->ds[ids] = '0';
5240Sstevel@tonic-gate 			}
5250Sstevel@tonic-gate 			pd->ndigits = ids;
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 		decimal_round(pm, pd, ps, round, sticky);
5280Sstevel@tonic-gate 	} else {		/* Combine integer and fraction for F format. */
5290Sstevel@tonic-gate 		if (pm->ndigits >= 0) {	/* Normal F format. */
5300Sstevel@tonic-gate 			if ((intdigs + pm->ndigits) >= DECIMAL_STRING_LENGTH)
5310Sstevel@tonic-gate 				goto overflow;
5320Sstevel@tonic-gate 			for (ids = 0; ids < intsigs; ids++)
5330Sstevel@tonic-gate 				pd->ds[ids] = is[ids];
5340Sstevel@tonic-gate 			for (; ids < intdigs; ids++)
5350Sstevel@tonic-gate 				pd->ds[ids] = '0';
5360Sstevel@tonic-gate 			/* Copy integer digits. */
5370Sstevel@tonic-gate 			idsbound = fracdigs;
5380Sstevel@tonic-gate 			if (idsbound > pm->ndigits)
5390Sstevel@tonic-gate 				idsbound = pm->ndigits;
5400Sstevel@tonic-gate 			if (fraczeros < idsbound)	/* Compute number of
5410Sstevel@tonic-gate 							 * leading zeros
5420Sstevel@tonic-gate 							 * required. */
5430Sstevel@tonic-gate 				lzbound = fraczeros;
5440Sstevel@tonic-gate 			else
5450Sstevel@tonic-gate 				lzbound = idsbound;
5460Sstevel@tonic-gate 			for (i = 0; (i < lzbound); i++)
5470Sstevel@tonic-gate 				pd->ds[ids++] = '0';
5480Sstevel@tonic-gate 			for (; (i < idsbound); i++)
5490Sstevel@tonic-gate 				pd->ds[ids++] = fs[i - fraczeros];	/* Copy fraction digits. */
5500Sstevel@tonic-gate 			for (; i < pm->ndigits; i++)
5510Sstevel@tonic-gate 				pd->ds[ids++] = '0';
5520Sstevel@tonic-gate 			/* Copy trailing zeros if necessary. */
5530Sstevel@tonic-gate 			pd->ndigits = ids;
5540Sstevel@tonic-gate 			pd->exponent = intdigs - ids;
5550Sstevel@tonic-gate 			i -= fraczeros;	/* Don't worry about leading zeros
5560Sstevel@tonic-gate 					 * from now on, we're just rounding */
5570Sstevel@tonic-gate 			if (i < fracsigs) {	/* Gather rounding info.  */
5580Sstevel@tonic-gate 				if (i < 0)
5590Sstevel@tonic-gate 					round = '0';
5600Sstevel@tonic-gate 				else
5610Sstevel@tonic-gate 					round = fs[i];
5620Sstevel@tonic-gate 				i++;
5630Sstevel@tonic-gate 				if (sticky == 0) {	/* Find out if remainder
5640Sstevel@tonic-gate 							 * is exact. */
5650Sstevel@tonic-gate 					if (i < 0)
5660Sstevel@tonic-gate 						i = 0;
5670Sstevel@tonic-gate 					for (; (fs[i] == '0') && (i < fracsigs); i++);
5680Sstevel@tonic-gate 					if (i < fracsigs)
5690Sstevel@tonic-gate 						sticky = 1;
5700Sstevel@tonic-gate 				}
5710Sstevel@tonic-gate 			}
5720Sstevel@tonic-gate 			decimal_round(pm, pd, ps, round, sticky);
5730Sstevel@tonic-gate 		} else {	/* Bizarre F format - round to left of point. */
5740Sstevel@tonic-gate 			int             roundpos = -pm->ndigits;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 			if (intdigs >= DECIMAL_STRING_LENGTH)
5770Sstevel@tonic-gate 				goto overflow;
5780Sstevel@tonic-gate 			if (roundpos >= DECIMAL_STRING_LENGTH)
5790Sstevel@tonic-gate 				goto overflow;
5800Sstevel@tonic-gate 			if (intdigs <= roundpos) {	/* Not enough integer
5810Sstevel@tonic-gate 							 * digits. */
5820Sstevel@tonic-gate 				if (intdigs == roundpos) {
5830Sstevel@tonic-gate 					round = is[0];
5840Sstevel@tonic-gate 					i = 1;
5850Sstevel@tonic-gate 				} else {
5860Sstevel@tonic-gate 					round = '0';
5870Sstevel@tonic-gate 					i = 0;
5880Sstevel@tonic-gate 				}
5890Sstevel@tonic-gate 				for (; (is[i] == '0') && (i < intsigs); i++);
5900Sstevel@tonic-gate 				/* Search for sticky bits. */
5910Sstevel@tonic-gate 				if (i < intsigs)
5920Sstevel@tonic-gate 					sticky = 1;
5930Sstevel@tonic-gate 				pd->ndigits = 0;
5940Sstevel@tonic-gate 			} else {/* Some integer digits do not get rounded
5950Sstevel@tonic-gate 				 * away. */
5960Sstevel@tonic-gate #ifdef _NO_GOOD
5970Sstevel@tonic-gate 				for (ids = 0; ids < (intsigs - roundpos); ids++)
5980Sstevel@tonic-gate 					pd->ds[ids] = is[ids];
5990Sstevel@tonic-gate 				for (ids = 0; ids < (intdigs - roundpos); ids++)
6000Sstevel@tonic-gate 					pd->ds[ids] = '0';
6010Sstevel@tonic-gate #else
6020Sstevel@tonic-gate                                  {
6030Sstevel@tonic-gate                                          int             ncopy = intsigs - roundpos;
6040Sstevel@tonic-gate                                          if (ncopy > 0) {
6050Sstevel@tonic-gate                                                  /* Copy integer digits. */
6060Sstevel@tonic-gate                                                  (void) memcpy(&(pd->ds[0]), &(is[0]), ncopy);
6070Sstevel@tonic-gate                                                  ids = ncopy;
6080Sstevel@tonic-gate                                          }
6090Sstevel@tonic-gate                                  }
6100Sstevel@tonic-gate                                  {
6110Sstevel@tonic-gate                                          int             ncopy = intdigs - roundpos - ids ;
6120Sstevel@tonic-gate                                          if (ncopy > 0) {
6130Sstevel@tonic-gate                                                  (void) memset(&(pd->ds[ids]), '0', ncopy);
6140Sstevel@tonic-gate                                                  ids += ncopy;
6150Sstevel@tonic-gate                                          }
6160Sstevel@tonic-gate                                  }
6170Sstevel@tonic-gate #endif /* _NO_GOOD */
6180Sstevel@tonic-gate 				/* Copy integer digits. */
6190Sstevel@tonic-gate 				pd->ndigits = ids;
6200Sstevel@tonic-gate 				if (ids < intsigs) {	/* Inexact. */
6210Sstevel@tonic-gate 					round = is[ids++];
6220Sstevel@tonic-gate 					for (; (is[ids] == '0') && (ids < intsigs); ids++);
6230Sstevel@tonic-gate 					/* Search for non-zero digits. */
6240Sstevel@tonic-gate 					if (ids < intsigs)
6250Sstevel@tonic-gate 						sticky = 1;
6260Sstevel@tonic-gate 				}
6270Sstevel@tonic-gate 			}
6280Sstevel@tonic-gate 			if (fx.fpclass != fp_zero)
6290Sstevel@tonic-gate 				sticky = 1;
6300Sstevel@tonic-gate 			decimal_round(pm, pd, ps, round, sticky);
6310Sstevel@tonic-gate 			for (i = pd->ndigits; i < (pd->ndigits + roundpos); i++)
6320Sstevel@tonic-gate 				pd->ds[i] = '0';	/* Blank out rounded
6330Sstevel@tonic-gate 							 * away digits. */
6340Sstevel@tonic-gate 			pd->exponent = 0;
6350Sstevel@tonic-gate 			pd->ndigits = i;
6360Sstevel@tonic-gate 			pd->ds[i] = 0;	/* Terminate string. */
6370Sstevel@tonic-gate 		}
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate void
double_to_decimal(double * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)642*722Smuffin double_to_decimal(double *px, decimal_mode *pm, decimal_record *pd,
643*722Smuffin     fp_exception_field_type *ps)
6440Sstevel@tonic-gate {
6450Sstevel@tonic-gate 	double_equivalence kluge;
6460Sstevel@tonic-gate 	unpacked        u;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	*ps = 0;		/* Initialize *ps. */
6490Sstevel@tonic-gate 	kluge.x = *px;
6500Sstevel@tonic-gate 	pd->sign = kluge.f.msw.sign;
6510Sstevel@tonic-gate 	pd->fpclass = _class_double(px);
6520Sstevel@tonic-gate 	switch (pd->fpclass) {
6530Sstevel@tonic-gate 	case fp_zero:
6540Sstevel@tonic-gate 		break;
6550Sstevel@tonic-gate 	case fp_infinity:
6560Sstevel@tonic-gate 		break;
6570Sstevel@tonic-gate 	case fp_quiet:
6580Sstevel@tonic-gate 		break;
6590Sstevel@tonic-gate 	case fp_signaling:
6600Sstevel@tonic-gate 		break;
6610Sstevel@tonic-gate 	default:
6620Sstevel@tonic-gate 		_unpack_double(&u, &kluge.x);
6630Sstevel@tonic-gate 		_unpacked_to_decimal(&u, pm, pd, ps);
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate void
quadruple_to_decimal(quadruple * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)668*722Smuffin quadruple_to_decimal(quadruple *px, decimal_mode *pm, decimal_record *pd,
669*722Smuffin     fp_exception_field_type *ps)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	quadruple_equivalence kluge;
6720Sstevel@tonic-gate 	unpacked        u;
6730Sstevel@tonic-gate 	int             i;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	*ps = 0;		/* Initialize *ps - no exceptions. */
6760Sstevel@tonic-gate 	for (i = 0; i < 4; i++)
6770Sstevel@tonic-gate #ifdef __STDC__
6780Sstevel@tonic-gate 		kluge.x = *px;
6790Sstevel@tonic-gate #else
6800Sstevel@tonic-gate 		kluge.x.u[i] = px->u[i];
6810Sstevel@tonic-gate #endif
6820Sstevel@tonic-gate 	pd->sign = kluge.f.msw.sign;
6830Sstevel@tonic-gate 	pd->fpclass = _class_quadruple(px);
6840Sstevel@tonic-gate 	switch (pd->fpclass) {
6850Sstevel@tonic-gate 	case fp_zero:
6860Sstevel@tonic-gate 		break;
6870Sstevel@tonic-gate 	case fp_infinity:
6880Sstevel@tonic-gate 		break;
6890Sstevel@tonic-gate 	case fp_quiet:
6900Sstevel@tonic-gate 		break;
6910Sstevel@tonic-gate 	case fp_signaling:
6920Sstevel@tonic-gate 		break;
6930Sstevel@tonic-gate 	default:
6940Sstevel@tonic-gate 		_unpack_quadruple(&u, px);
6950Sstevel@tonic-gate 		_unpacked_to_decimal(&u, pm, pd, ps);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate }
698