xref: /onnv-gate/usr/src/lib/libc/port/fp/double_decim.c (revision 8378:27908cc5841e)
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
56812Sraf  * Common Development and Distribution License (the "License").
66812Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
216812Sraf 
220Sstevel@tonic-gate /*
236812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Conversion from binary to decimal floating point
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
316812Sraf #include "lint.h"
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include "base_conversion.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate /*
360Sstevel@tonic-gate  * Any sensible programmer would inline the following routine where
370Sstevel@tonic-gate  * it is used below.  Unfortunately, the Sun SPARC compilers are not
380Sstevel@tonic-gate  * consistent in generating efficient code for this, so inlining it
390Sstevel@tonic-gate  * as written can cause the *_to_decimal functions to take twice as
400Sstevel@tonic-gate  * long in some cases.
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  * We might be tempted, then, to rewrite the source to match the most
430Sstevel@tonic-gate  * efficient code the compilers generate and inline that.  Alas, the
440Sstevel@tonic-gate  * most efficient code on SPARC uses 32x32->64 bit multiply, which
450Sstevel@tonic-gate  * can't be expressed directly in source code.  We could use long long,
460Sstevel@tonic-gate  * which would imply 64x64->64 bit multiply; this would work perfectly
470Sstevel@tonic-gate  * well on SPARC in v8plus mode.  But as of Solaris 10, libc for SPARC
480Sstevel@tonic-gate  * is still built in v8 mode, and of course, x86 is another story.
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  * We could also choose to use an inline template to get the most
510Sstevel@tonic-gate  * efficient code without incurring the full cost of a function call.
520Sstevel@tonic-gate  * Since I expect that would not buy much performance gain, and I
530Sstevel@tonic-gate  * prefer to avoid using inline templates for things that can be
540Sstevel@tonic-gate  * written in a perfectly straightforward way in C, I've settled
550Sstevel@tonic-gate  * for this implementation.  I hope that someday the compilers will
560Sstevel@tonic-gate  * get less flaky and/or someone will come up with a better way to
570Sstevel@tonic-gate  * do this.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate static unsigned int
__quorem10000(unsigned int x,unsigned short * pr)600Sstevel@tonic-gate __quorem10000(unsigned int x, unsigned short *pr)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	*pr = x % 10000;
630Sstevel@tonic-gate 	return (x / 10000);
640Sstevel@tonic-gate }
650Sstevel@tonic-gate 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * Convert the integer part of a nonzero base-2^16 _big_float *pb
680Sstevel@tonic-gate  * to base 10^4 in **ppd.  The converted value is accurate to nsig
690Sstevel@tonic-gate  * significant digits.  On exit, *sticky is nonzero if *pb had a
700Sstevel@tonic-gate  * nonzero fractional part.  If pb->exponent > 0 and **ppd is not
710Sstevel@tonic-gate  * large enough to hold the final converted value (i.e., the con-
720Sstevel@tonic-gate  * verted significand scaled by 2^pb->exponent), then on exit,
730Sstevel@tonic-gate  * *ppd will point to a newly allocated _big_float, which must be
740Sstevel@tonic-gate  * freed by the caller.  (The number of significant digits we need
750Sstevel@tonic-gate  * should fit in pd, but __big_float_times_power may allocate new
760Sstevel@tonic-gate  * storage anyway because we could be multiplying by as much as
770Sstevel@tonic-gate  * 2^16271, which would require more than 4000 digits.)
780Sstevel@tonic-gate  *
790Sstevel@tonic-gate  * This routine does not check that **ppd is large enough to hold
800Sstevel@tonic-gate  * the result of converting the significand of *pb.
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate static void
__big_binary_to_big_decimal(_big_float * pb,int nsig,_big_float ** ppd,int * sticky)830Sstevel@tonic-gate __big_binary_to_big_decimal(_big_float *pb, int nsig, _big_float **ppd,
840Sstevel@tonic-gate     int *sticky)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	_big_float	*pd;
870Sstevel@tonic-gate 	int		i, j, len, s;
880Sstevel@tonic-gate 	unsigned int	carry;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	pd = *ppd;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	/* convert pb a digit at a time, most significant first */
930Sstevel@tonic-gate 	if (pb->bexponent + ((pb->blength - 1) << 4) >= 0) {
940Sstevel@tonic-gate 		carry = pb->bsignificand[pb->blength - 1];
950Sstevel@tonic-gate 		pd->bsignificand[1] = __quorem10000(carry,
960Sstevel@tonic-gate 		    &pd->bsignificand[0]);
970Sstevel@tonic-gate 		len = (pd->bsignificand[1])? 2 : 1;
980Sstevel@tonic-gate 		for (i = pb->blength - 2; i >= 0 &&
990Sstevel@tonic-gate 		    pb->bexponent + (i << 4) >= 0; i--) {
1000Sstevel@tonic-gate 			/* multiply pd by 2^16 and add next digit */
1010Sstevel@tonic-gate 			carry = pb->bsignificand[i];
1020Sstevel@tonic-gate 			for (j = 0; j < len; j++) {
1030Sstevel@tonic-gate 				carry += (unsigned int)pd->bsignificand[j]
1040Sstevel@tonic-gate 				    << 16;
1050Sstevel@tonic-gate 				carry = __quorem10000(carry,
1060Sstevel@tonic-gate 				    &pd->bsignificand[j]);
1070Sstevel@tonic-gate 			}
1080Sstevel@tonic-gate 			while (carry != 0) {
1090Sstevel@tonic-gate 				carry = __quorem10000(carry,
1100Sstevel@tonic-gate 				    &pd->bsignificand[j]);
1110Sstevel@tonic-gate 				j++;
1120Sstevel@tonic-gate 			}
1130Sstevel@tonic-gate 			len = j;
1140Sstevel@tonic-gate 		}
1150Sstevel@tonic-gate 	} else {
1160Sstevel@tonic-gate 		i = pb->blength - 1;
1170Sstevel@tonic-gate 		len = 0;
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* convert any partial digit */
1210Sstevel@tonic-gate 	if (i >= 0 && pb->bexponent + (i << 4) > -16) {
1220Sstevel@tonic-gate 		s = pb->bexponent + (i << 4) + 16;
1230Sstevel@tonic-gate 		/* multiply pd by 2^s and add partial digit */
1240Sstevel@tonic-gate 		carry = pb->bsignificand[i] >> (16 - s);
1250Sstevel@tonic-gate 		for (j = 0; j < len; j++) {
1260Sstevel@tonic-gate 			carry += (unsigned int)pd->bsignificand[j] << s;
1270Sstevel@tonic-gate 			carry = __quorem10000(carry, &pd->bsignificand[j]);
1280Sstevel@tonic-gate 		}
1290Sstevel@tonic-gate 		while (carry != 0) {
1300Sstevel@tonic-gate 			carry = __quorem10000(carry, &pd->bsignificand[j]);
1310Sstevel@tonic-gate 			j++;
1320Sstevel@tonic-gate 		}
1330Sstevel@tonic-gate 		len = j;
1340Sstevel@tonic-gate 		s = pb->bsignificand[i] & ((1 << (16 - s)) - 1);
1350Sstevel@tonic-gate 		i--;
1360Sstevel@tonic-gate 	} else {
1370Sstevel@tonic-gate 		s = 0;
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	pd->blength = len;
1410Sstevel@tonic-gate 	pd->bexponent = 0;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	/* continue accumulating sticky flag */
1440Sstevel@tonic-gate 	while (i >= 0)
1450Sstevel@tonic-gate 		s |= pb->bsignificand[i--];
1460Sstevel@tonic-gate 	*sticky = s;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	if (pb->bexponent > 0) {
1490Sstevel@tonic-gate 		/* scale pd by 2^pb->bexponent */
1500Sstevel@tonic-gate 		__big_float_times_power(pd, 2, pb->bexponent, nsig, ppd);
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * Convert a base-10^4 _big_float *pf to a decimal string in *pd,
1560Sstevel@tonic-gate  * rounding according to the modes in *pm and recording any exceptions
1570Sstevel@tonic-gate  * in *ps.  If sticky is nonzero, then additional nonzero digits are
1580Sstevel@tonic-gate  * assumed to follow those in *pf.  pd->sign must have already been
1590Sstevel@tonic-gate  * filled in, and pd->fpclass is not modified.  The resulting string
1600Sstevel@tonic-gate  * is stored in pd->ds, terminated by a null byte.  The length of this
1610Sstevel@tonic-gate  * string is stored in pd->ndigits, and the corresponding exponent
1620Sstevel@tonic-gate  * is stored in pd->exponent.  If the converted value is not exact,
1630Sstevel@tonic-gate  * the inexact flag is set in *ps.
1640Sstevel@tonic-gate  *
1650Sstevel@tonic-gate  * When pm->df == fixed_form, we may discover that the result would
1660Sstevel@tonic-gate  * have more than DECIMAL_STRING_LENGTH - 1 digits.  In this case,
1670Sstevel@tonic-gate  * we put DECIMAL_STRING_LENGTH - 1 digits into *pd, adjusting both
1680Sstevel@tonic-gate  * the exponent and the decimal place at which the value is rounded
1690Sstevel@tonic-gate  * as need be, and we set the overflow flag in *ps.  (Raising overflow
1700Sstevel@tonic-gate  * is a bug, but we have to do it to maintain backward compatibility.)
1710Sstevel@tonic-gate  *
1720Sstevel@tonic-gate  * *pf may be modified.
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate static void
__big_decimal_to_string(_big_float * pf,int sticky,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)1750Sstevel@tonic-gate __big_decimal_to_string(_big_float *pf, int sticky, decimal_mode *pm,
1760Sstevel@tonic-gate     decimal_record *pd, fp_exception_field_type *ps)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	unsigned short	d;
1790Sstevel@tonic-gate 	int		e, er, efirst, elast, i, is, j;
1800Sstevel@tonic-gate 	char		s[4], round;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* set e = floor(log10(*pf)) */
1830Sstevel@tonic-gate 	i = pf->blength - 1;
1840Sstevel@tonic-gate 	if (i < 0) {
1850Sstevel@tonic-gate 		e = pf->bexponent = -DECIMAL_STRING_LENGTH - 2;
1860Sstevel@tonic-gate 	} else {
1870Sstevel@tonic-gate 		e = pf->bexponent + (i << 2);
1880Sstevel@tonic-gate 		d = pf->bsignificand[i];
1890Sstevel@tonic-gate 		if (d >= 1000)
1900Sstevel@tonic-gate 			e += 3;
1910Sstevel@tonic-gate 		else if (d >= 100)
1920Sstevel@tonic-gate 			e += 2;
1930Sstevel@tonic-gate 		else if (d >= 10)
1940Sstevel@tonic-gate 			e++;
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	/*
1980Sstevel@tonic-gate 	 * Determine the power of ten after which to round and the
1990Sstevel@tonic-gate 	 * powers corresponding to the first and last digits desired
2000Sstevel@tonic-gate 	 * in the result.
2010Sstevel@tonic-gate 	 */
2020Sstevel@tonic-gate 	if (pm->df == fixed_form) {
2030Sstevel@tonic-gate 		/* F format */
2040Sstevel@tonic-gate 		er = -pm->ndigits;
2050Sstevel@tonic-gate 		if (er < 0) {
2060Sstevel@tonic-gate 			efirst = (e >= 0)? e : -1;
2070Sstevel@tonic-gate 			elast = er;
2080Sstevel@tonic-gate 		} else {
2090Sstevel@tonic-gate 			efirst = (e >= er)? e : ((er > 0)? er - 1 : 0);
2100Sstevel@tonic-gate 			elast = 0;
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 		/* check for possible overflow of pd->ds */
2140Sstevel@tonic-gate 		if (efirst - elast >= DECIMAL_STRING_LENGTH - 1) {
2150Sstevel@tonic-gate 			efirst = e;
2160Sstevel@tonic-gate 			elast = e - DECIMAL_STRING_LENGTH + 2;
2170Sstevel@tonic-gate 			if (er < elast)
2180Sstevel@tonic-gate 				er = elast;
2190Sstevel@tonic-gate 			*ps |= 1 << fp_overflow;
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 	} else {
2220Sstevel@tonic-gate 		/* E format */
2230Sstevel@tonic-gate 		efirst = e;
2240Sstevel@tonic-gate 		elast = er = e - pm->ndigits + 1;
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/* retrieve digits down to the (er - 1) place */
2280Sstevel@tonic-gate 	is = 0;
2290Sstevel@tonic-gate 	for (e = efirst; e >= pf->bexponent + (pf->blength << 2) &&
2300Sstevel@tonic-gate 	    e >= er - 1; e--)
2310Sstevel@tonic-gate 		pd->ds[is++] = '0';
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	i = pf->blength - 1;
2340Sstevel@tonic-gate 	j = 3 - ((e - pf->bexponent) & 3);
2350Sstevel@tonic-gate 	if (j > 0 && e >= er - 1) {
2360Sstevel@tonic-gate 		__four_digits_quick(pf->bsignificand[i], s);
2370Sstevel@tonic-gate 		while (j <= 3 && e >= er - 1) {
2380Sstevel@tonic-gate 			pd->ds[is++] = s[j++];
2390Sstevel@tonic-gate 			e--;
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 		while (j <= 3)
2420Sstevel@tonic-gate 			sticky |= (s[j++] - '0');
2430Sstevel@tonic-gate 		i--;
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	while ((i | (e - er - 2)) >= 0) {  /* i >= 0 && e >= er + 2 */
2470Sstevel@tonic-gate 		__four_digits_quick(pf->bsignificand[i], pd->ds + is);
2480Sstevel@tonic-gate 		is += 4;
2490Sstevel@tonic-gate 		e -= 4;
2500Sstevel@tonic-gate 		i--;
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	if (i >= 0) {
2540Sstevel@tonic-gate 		if (e >= er - 1) {
2550Sstevel@tonic-gate 			__four_digits_quick(pf->bsignificand[i], s);
2560Sstevel@tonic-gate 			for (j = 0; e >= er - 1; j++) {
2570Sstevel@tonic-gate 				pd->ds[is++] = s[j];
2580Sstevel@tonic-gate 				e--;
2590Sstevel@tonic-gate 			}
2600Sstevel@tonic-gate 			while (j <= 3)
2610Sstevel@tonic-gate 				sticky |= (s[j++] - '0');
2620Sstevel@tonic-gate 			i--;
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 	} else {
2650Sstevel@tonic-gate 		while (e-- >= er - 1)
2660Sstevel@tonic-gate 			pd->ds[is++] = '0';
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/* collect rounding information */
2700Sstevel@tonic-gate 	round = pd->ds[--is];
2710Sstevel@tonic-gate 	while (i >= 0)
2720Sstevel@tonic-gate 		sticky |= pf->bsignificand[i--];
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/* add more trailing zeroes if need be */
2750Sstevel@tonic-gate 	for (e = er - 1; e >= elast; e--)
2760Sstevel@tonic-gate 		pd->ds[is++] = '0';
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	pd->exponent = elast;
2790Sstevel@tonic-gate 	pd->ndigits = is;
2800Sstevel@tonic-gate 	pd->ds[is] = '\0';
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	/* round */
2830Sstevel@tonic-gate 	if (round == '0' && sticky == 0)
2840Sstevel@tonic-gate 		return;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	*ps |= 1 << fp_inexact;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	switch (pm->rd) {
2890Sstevel@tonic-gate 	case fp_nearest:
2900Sstevel@tonic-gate 		if (round < '5' || (round == '5' && sticky == 0 &&
2910Sstevel@tonic-gate 		    (is <= 0 || (pd->ds[is - 1] & 1) == 0)))
2920Sstevel@tonic-gate 			return;
2930Sstevel@tonic-gate 		break;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	case fp_positive:
2960Sstevel@tonic-gate 		if (pd->sign)
2970Sstevel@tonic-gate 			return;
2980Sstevel@tonic-gate 		break;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	case fp_negative:
3010Sstevel@tonic-gate 		if (!pd->sign)
3020Sstevel@tonic-gate 			return;
3030Sstevel@tonic-gate 		break;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	default:
3060Sstevel@tonic-gate 		return;
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/* round up */
3100Sstevel@tonic-gate 	for (i = efirst - er; i >= 0 && pd->ds[i] == '9'; i--)
3110Sstevel@tonic-gate 		pd->ds[i] = '0';
3120Sstevel@tonic-gate 	if (i >= 0) {
3130Sstevel@tonic-gate 		(pd->ds[i])++;
3140Sstevel@tonic-gate 	} else {
3150Sstevel@tonic-gate 		/* rounding carry out has occurred */
3160Sstevel@tonic-gate 		pd->ds[0] = '1';
3170Sstevel@tonic-gate 		if (pm->df == floating_form) {
3180Sstevel@tonic-gate 			pd->exponent++;
3190Sstevel@tonic-gate 		} else if (is == DECIMAL_STRING_LENGTH - 1) {
3200Sstevel@tonic-gate 			pd->exponent++;
3210Sstevel@tonic-gate 			*ps |= 1 << fp_overflow;
3220Sstevel@tonic-gate 		} else {
3230Sstevel@tonic-gate 			if (is > 0)
3240Sstevel@tonic-gate 				pd->ds[is] = '0';
3250Sstevel@tonic-gate 			is++;
3260Sstevel@tonic-gate 			pd->ndigits = is;
3270Sstevel@tonic-gate 			pd->ds[is] = '\0';
3280Sstevel@tonic-gate 		}
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * Convert a binary floating point value represented by *pf to a
3340Sstevel@tonic-gate  * decimal record *pd according to the modes in *pm.  Any exceptions
3350Sstevel@tonic-gate  * incurred are passed back via *ps.
3360Sstevel@tonic-gate  */
3370Sstevel@tonic-gate static void
__bigfloat_to_decimal(_big_float * bf,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)3380Sstevel@tonic-gate __bigfloat_to_decimal(_big_float *bf, decimal_mode *pm, decimal_record *pd,
3390Sstevel@tonic-gate     fp_exception_field_type *ps)
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate 	_big_float	*pbf, *pbd, d;
3420Sstevel@tonic-gate 	int		sticky, powten, sigbits, sigdigits, i;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * If pm->ndigits is too large or too small, set the overflow
3460Sstevel@tonic-gate 	 * flag in *ps and do nothing.  (Raising overflow is a bug,
3470Sstevel@tonic-gate 	 * but we have to do it to maintain backward compatibility.)
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 	if (pm->ndigits >= DECIMAL_STRING_LENGTH || pm->ndigits <=
3500Sstevel@tonic-gate 	    ((pm->df == floating_form)? 0 : -DECIMAL_STRING_LENGTH)) {
3510Sstevel@tonic-gate 		*ps = 1 << fp_overflow;
3520Sstevel@tonic-gate 		return;
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	pbf = bf;
3560Sstevel@tonic-gate 	powten = 0;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/* pre-scale to get the digits we want into the integer part */
3590Sstevel@tonic-gate 	if (pm->df == fixed_form) {
3600Sstevel@tonic-gate 		/* F format */
3610Sstevel@tonic-gate 		if (pm->ndigits >= 0 && bf->bexponent < 0) {
3620Sstevel@tonic-gate 			/*
3630Sstevel@tonic-gate 			 * Scale by 10^min(-bf->bexponent, pm->ndigits + 1).
3640Sstevel@tonic-gate 			 */
3650Sstevel@tonic-gate 			powten = pm->ndigits + 1;
3660Sstevel@tonic-gate 			if (powten > -bf->bexponent)
3670Sstevel@tonic-gate 				powten = -bf->bexponent;
3680Sstevel@tonic-gate 			/*
3690Sstevel@tonic-gate 			 * Take sigbits large enough to get all integral
3700Sstevel@tonic-gate 			 * digits correct.
3710Sstevel@tonic-gate 			 */
3720Sstevel@tonic-gate 			sigbits = bf->bexponent + (bf->blength << 4) +
3730Sstevel@tonic-gate 			    (((powten * 217706) + 65535) >> 16);
3740Sstevel@tonic-gate 			if (sigbits < 1)
3750Sstevel@tonic-gate 				sigbits = 1;
3760Sstevel@tonic-gate 			__big_float_times_power(bf, 10, powten, sigbits, &pbf);
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 		sigdigits = DECIMAL_STRING_LENGTH + 1;
3790Sstevel@tonic-gate 	} else {
3800Sstevel@tonic-gate 		/* E format */
3810Sstevel@tonic-gate 		if (bf->bexponent < 0) {
3820Sstevel@tonic-gate 			/* i is a lower bound on log2(x) */
3830Sstevel@tonic-gate 			i = bf->bexponent + ((bf->blength - 1) << 4);
3840Sstevel@tonic-gate 			if (i <= 0 || ((i * 19728) >> 16) < pm->ndigits + 1) {
3850Sstevel@tonic-gate 				/*
3860Sstevel@tonic-gate 				 * Scale by 10^min(-bf->bexponent,
3870Sstevel@tonic-gate 				 * pm->ndigits + 1 + u) where u is
3880Sstevel@tonic-gate 				 * an upper bound on -log10(x).
3890Sstevel@tonic-gate 				 */
3900Sstevel@tonic-gate 				powten = pm->ndigits + 1;
3910Sstevel@tonic-gate 				if (i < 0)
3920Sstevel@tonic-gate 					powten += ((-i * 19729) + 65535) >> 16;
3930Sstevel@tonic-gate 				else if (i > 0)
3940Sstevel@tonic-gate 					powten -= (i * 19728) >> 16;
3950Sstevel@tonic-gate 				if (powten > -bf->bexponent)
3960Sstevel@tonic-gate 					powten = -bf->bexponent;
3970Sstevel@tonic-gate 				/*
3980Sstevel@tonic-gate 				 * Take sigbits large enough to get
3990Sstevel@tonic-gate 				 * all integral digits correct.
4000Sstevel@tonic-gate 				 */
4010Sstevel@tonic-gate 				sigbits = i + 16 +
4020Sstevel@tonic-gate 				    (((powten * 217706) + 65535) >> 16);
4030Sstevel@tonic-gate 				__big_float_times_power(bf, 10, powten,
4040Sstevel@tonic-gate 				    sigbits, &pbf);
4050Sstevel@tonic-gate 			}
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 		sigdigits = pm->ndigits + 2;
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	/* convert to base 10^4 */
4110Sstevel@tonic-gate 	d.bsize = _BIG_FLOAT_SIZE;
4120Sstevel@tonic-gate 	pbd = &d;
4130Sstevel@tonic-gate 	__big_binary_to_big_decimal(pbf, sigdigits, &pbd, &sticky);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	/* adjust pbd->bexponent based on the scale factor above */
4160Sstevel@tonic-gate 	pbd->bexponent -= powten;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/* convert to ASCII */
4190Sstevel@tonic-gate 	__big_decimal_to_string(pbd, sticky, pm, pd, ps);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	if (pbf != bf)
4220Sstevel@tonic-gate 		(void) free((void *)pbf);
4230Sstevel@tonic-gate 	if (pbd != &d)
4240Sstevel@tonic-gate 		(void) free((void *)pbd);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate /* remove trailing zeroes from the significand of p */
4280Sstevel@tonic-gate static void
__shorten(_big_float * p)4290Sstevel@tonic-gate __shorten(_big_float *p)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	int	length = p->blength;
4320Sstevel@tonic-gate 	int	zeros, i;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/* count trailing zeros */
4350Sstevel@tonic-gate 	for (zeros = 0; zeros < length && p->bsignificand[zeros] == 0; zeros++)
4360Sstevel@tonic-gate 		;
4370Sstevel@tonic-gate 	if (zeros) {
4380Sstevel@tonic-gate 		length -= zeros;
4390Sstevel@tonic-gate 		p->bexponent += zeros << 4;
4400Sstevel@tonic-gate 		for (i = 0; i < length; i++)
4410Sstevel@tonic-gate 			p->bsignificand[i] = p->bsignificand[i + zeros];
4420Sstevel@tonic-gate 		p->blength = length;
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * Unpack a normal or subnormal double into a _big_float.
4480Sstevel@tonic-gate  */
4490Sstevel@tonic-gate static void
__double_to_bigfloat(double * px,_big_float * pf)4500Sstevel@tonic-gate __double_to_bigfloat(double *px, _big_float *pf)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	double_equivalence	*x;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	x = (double_equivalence *)px;
4550Sstevel@tonic-gate 	pf->bsize = _BIG_FLOAT_SIZE;
4560Sstevel@tonic-gate 	pf->bexponent = x->f.msw.exponent - DOUBLE_BIAS - 52;
4570Sstevel@tonic-gate 	pf->blength = 4;
4580Sstevel@tonic-gate 	pf->bsignificand[0] = x->f.significand2 & 0xffff;
4590Sstevel@tonic-gate 	pf->bsignificand[1] = x->f.significand2 >> 16;
4600Sstevel@tonic-gate 	pf->bsignificand[2] = x->f.msw.significand & 0xffff;
4610Sstevel@tonic-gate 	pf->bsignificand[3] = x->f.msw.significand >> 16;
4620Sstevel@tonic-gate 	if (x->f.msw.exponent == 0) {
4630Sstevel@tonic-gate 		pf->bexponent++;
4640Sstevel@tonic-gate 		while (pf->bsignificand[pf->blength - 1] == 0)
4650Sstevel@tonic-gate 			pf->blength--;
4660Sstevel@tonic-gate 	} else {
4670Sstevel@tonic-gate 		pf->bsignificand[3] += 0x10;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 	__shorten(pf);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate  * Unpack a normal or subnormal extended into a _big_float.
4740Sstevel@tonic-gate  */
4750Sstevel@tonic-gate static void
__extended_to_bigfloat(extended * px,_big_float * pf)4760Sstevel@tonic-gate __extended_to_bigfloat(extended *px, _big_float *pf)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate 	extended_equivalence	*x;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	x = (extended_equivalence *)px;
4810Sstevel@tonic-gate 	pf->bsize = _BIG_FLOAT_SIZE;
4820Sstevel@tonic-gate 	pf->bexponent = x->f.msw.exponent - EXTENDED_BIAS - 63;
4830Sstevel@tonic-gate 	pf->blength = 4;
4840Sstevel@tonic-gate 	pf->bsignificand[0] = x->f.significand2 & 0xffff;
4850Sstevel@tonic-gate 	pf->bsignificand[1] = x->f.significand2 >> 16;
4860Sstevel@tonic-gate 	pf->bsignificand[2] = x->f.significand & 0xffff;
4870Sstevel@tonic-gate 	pf->bsignificand[3] = x->f.significand >> 16;
4880Sstevel@tonic-gate 	if (x->f.msw.exponent == 0) {
4890Sstevel@tonic-gate 		pf->bexponent++;
4900Sstevel@tonic-gate 		while (pf->bsignificand[pf->blength - 1] == 0)
4910Sstevel@tonic-gate 			pf->blength--;
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	__shorten(pf);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate /*
4970Sstevel@tonic-gate  * Unpack a normal or subnormal quad into a _big_float.
4980Sstevel@tonic-gate  */
4990Sstevel@tonic-gate static void
__quadruple_to_bigfloat(quadruple * px,_big_float * pf)5000Sstevel@tonic-gate __quadruple_to_bigfloat(quadruple *px, _big_float *pf)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 	quadruple_equivalence	*x;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	x = (quadruple_equivalence *)px;
5050Sstevel@tonic-gate 	pf->bsize = _BIG_FLOAT_SIZE;
5060Sstevel@tonic-gate 	pf->bexponent = x->f.msw.exponent - QUAD_BIAS - 112;
5070Sstevel@tonic-gate 	pf->bsignificand[0] = x->f.significand4 & 0xffff;
5080Sstevel@tonic-gate 	pf->bsignificand[1] = x->f.significand4 >> 16;
5090Sstevel@tonic-gate 	pf->bsignificand[2] = x->f.significand3 & 0xffff;
5100Sstevel@tonic-gate 	pf->bsignificand[3] = x->f.significand3 >> 16;
5110Sstevel@tonic-gate 	pf->bsignificand[4] = x->f.significand2 & 0xffff;
5120Sstevel@tonic-gate 	pf->bsignificand[5] = x->f.significand2 >> 16;
5130Sstevel@tonic-gate 	pf->bsignificand[6] = x->f.msw.significand;
5140Sstevel@tonic-gate 	if (x->f.msw.exponent == 0) {
5150Sstevel@tonic-gate 		pf->blength = 7;
5160Sstevel@tonic-gate 		pf->bexponent++;
5170Sstevel@tonic-gate 		while (pf->bsignificand[pf->blength - 1] == 0)
5180Sstevel@tonic-gate 			pf->blength--;
5190Sstevel@tonic-gate 	} else {
5200Sstevel@tonic-gate 		pf->blength = 8;
5210Sstevel@tonic-gate 		pf->bsignificand[7] = 1;
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 	__shorten(pf);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate /* PUBLIC ROUTINES */
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate void
single_to_decimal(single * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)5290Sstevel@tonic-gate single_to_decimal(single *px, decimal_mode *pm, decimal_record *pd,
5300Sstevel@tonic-gate     fp_exception_field_type *ps)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	single_equivalence	*kluge;
5330Sstevel@tonic-gate 	_big_float		bf;
5340Sstevel@tonic-gate 	fp_exception_field_type	ef;
5350Sstevel@tonic-gate 	double			x;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	kluge = (single_equivalence *)px;
5380Sstevel@tonic-gate 	pd->sign = kluge->f.msw.sign;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/* decide what to do based on the class of x */
5410Sstevel@tonic-gate 	if (kluge->f.msw.exponent == 0) {	/* 0 or subnormal */
5420Sstevel@tonic-gate 		if (kluge->f.msw.significand == 0) {
5430Sstevel@tonic-gate 			pd->fpclass = fp_zero;
5440Sstevel@tonic-gate 			*ps = 0;
5450Sstevel@tonic-gate 			return;
5460Sstevel@tonic-gate 		} else {
547*8378SDouglas.Priest@Sun.COM #if defined(__sparc) || defined(__amd64)
5480Sstevel@tonic-gate 			int	i;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 			pd->fpclass = fp_subnormal;
5510Sstevel@tonic-gate 			/*
552*8378SDouglas.Priest@Sun.COM 			 * On SPARC when nonstandard mode is enabled,
553*8378SDouglas.Priest@Sun.COM 			 * or on x64 when FTZ mode is enabled, simply
554*8378SDouglas.Priest@Sun.COM 			 * converting *px to double can flush a sub-
555*8378SDouglas.Priest@Sun.COM 			 * normal value to zero, so we have to go
556*8378SDouglas.Priest@Sun.COM 			 * through all this nonsense instead.
5570Sstevel@tonic-gate 			 */
5580Sstevel@tonic-gate 			i = *(int *)px;
5590Sstevel@tonic-gate 			x = (double)(i & ~0x80000000);
5600Sstevel@tonic-gate 			if (i < 0)
5610Sstevel@tonic-gate 				x = -x;
5620Sstevel@tonic-gate 			x *= 1.401298464324817070923730e-45; /* 2^-149 */
5630Sstevel@tonic-gate 			ef = 0;
5640Sstevel@tonic-gate 			if (__fast_double_to_decimal(&x, pm, pd, &ef)) {
5650Sstevel@tonic-gate 				__double_to_bigfloat(&x, &bf);
5660Sstevel@tonic-gate 				__bigfloat_to_decimal(&bf, pm, pd, &ef);
5670Sstevel@tonic-gate 			}
5680Sstevel@tonic-gate 			if (ef != 0)
5690Sstevel@tonic-gate 				__base_conversion_set_exception(ef);
5700Sstevel@tonic-gate 			*ps = ef;
5710Sstevel@tonic-gate 			return;
5720Sstevel@tonic-gate #else
5730Sstevel@tonic-gate 			pd->fpclass = fp_subnormal;
5740Sstevel@tonic-gate #endif
5750Sstevel@tonic-gate 		}
5760Sstevel@tonic-gate 	} else if (kluge->f.msw.exponent == 0xff) {	/* inf or nan */
5770Sstevel@tonic-gate 		if (kluge->f.msw.significand == 0)
5780Sstevel@tonic-gate 			pd->fpclass = fp_infinity;
5790Sstevel@tonic-gate 		else if (kluge->f.msw.significand >= 0x400000)
5800Sstevel@tonic-gate 			pd->fpclass = fp_quiet;
5810Sstevel@tonic-gate 		else
5820Sstevel@tonic-gate 			pd->fpclass = fp_signaling;
5830Sstevel@tonic-gate 		*ps = 0;
5840Sstevel@tonic-gate 		return;
5850Sstevel@tonic-gate 	} else {
5860Sstevel@tonic-gate 		pd->fpclass = fp_normal;
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	ef = 0;
5900Sstevel@tonic-gate 	x = *px;
5910Sstevel@tonic-gate 	if (__fast_double_to_decimal(&x, pm, pd, &ef)) {
5920Sstevel@tonic-gate 		__double_to_bigfloat(&x, &bf);
5930Sstevel@tonic-gate 		__bigfloat_to_decimal(&bf, pm, pd, &ef);
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 	if (ef != 0)
5960Sstevel@tonic-gate 		__base_conversion_set_exception(ef);
5970Sstevel@tonic-gate 	*ps = ef;
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate void
double_to_decimal(double * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)6010Sstevel@tonic-gate double_to_decimal(double *px, decimal_mode *pm, decimal_record *pd,
6020Sstevel@tonic-gate     fp_exception_field_type *ps)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate 	double_equivalence	*kluge;
6050Sstevel@tonic-gate 	_big_float		bf;
6060Sstevel@tonic-gate 	fp_exception_field_type	ef;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	kluge = (double_equivalence *)px;
6090Sstevel@tonic-gate 	pd->sign = kluge->f.msw.sign;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	/* decide what to do based on the class of x */
6120Sstevel@tonic-gate 	if (kluge->f.msw.exponent == 0) {	/* 0 or subnormal */
6130Sstevel@tonic-gate 		if (kluge->f.msw.significand == 0 &&
6140Sstevel@tonic-gate 		    kluge->f.significand2 == 0) {
6150Sstevel@tonic-gate 			pd->fpclass = fp_zero;
6160Sstevel@tonic-gate 			*ps = 0;
6170Sstevel@tonic-gate 			return;
6180Sstevel@tonic-gate 		} else {
6190Sstevel@tonic-gate 			pd->fpclass = fp_subnormal;
6200Sstevel@tonic-gate 		}
6210Sstevel@tonic-gate 	} else if (kluge->f.msw.exponent == 0x7ff) {	/* inf or nan */
6220Sstevel@tonic-gate 		if (kluge->f.msw.significand == 0 &&
6230Sstevel@tonic-gate 		    kluge->f.significand2 == 0)
6240Sstevel@tonic-gate 			pd->fpclass = fp_infinity;
6250Sstevel@tonic-gate 		else if (kluge->f.msw.significand >= 0x80000)
6260Sstevel@tonic-gate 			pd->fpclass = fp_quiet;
6270Sstevel@tonic-gate 		else
6280Sstevel@tonic-gate 			pd->fpclass = fp_signaling;
6290Sstevel@tonic-gate 		*ps = 0;
6300Sstevel@tonic-gate 		return;
6310Sstevel@tonic-gate 	} else {
6320Sstevel@tonic-gate 		pd->fpclass = fp_normal;
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	ef = 0;
6360Sstevel@tonic-gate 	if (__fast_double_to_decimal(px, pm, pd, &ef)) {
6370Sstevel@tonic-gate 		__double_to_bigfloat(px, &bf);
6380Sstevel@tonic-gate 		__bigfloat_to_decimal(&bf, pm, pd, &ef);
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 	if (ef != 0)
6410Sstevel@tonic-gate 		__base_conversion_set_exception(ef);
6420Sstevel@tonic-gate 	*ps = ef;
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate void
extended_to_decimal(extended * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)6460Sstevel@tonic-gate extended_to_decimal(extended *px, decimal_mode *pm, decimal_record *pd,
6470Sstevel@tonic-gate     fp_exception_field_type *ps)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate 	extended_equivalence	*kluge;
6500Sstevel@tonic-gate 	_big_float		bf;
6510Sstevel@tonic-gate 	fp_exception_field_type	ef;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	kluge = (extended_equivalence *)px;
6540Sstevel@tonic-gate 	pd->sign = kluge->f.msw.sign;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/* decide what to do based on the class of x */
6570Sstevel@tonic-gate 	if (kluge->f.msw.exponent == 0) {	/* 0 or subnormal */
6580Sstevel@tonic-gate 		if ((kluge->f.significand | kluge->f.significand2) == 0) {
6590Sstevel@tonic-gate 			pd->fpclass = fp_zero;
6600Sstevel@tonic-gate 			*ps = 0;
6610Sstevel@tonic-gate 			return;
6620Sstevel@tonic-gate 		} else {
6630Sstevel@tonic-gate 			/*
6640Sstevel@tonic-gate 			 * x could be a pseudo-denormal, but the distinction
6650Sstevel@tonic-gate 			 * doesn't matter
6660Sstevel@tonic-gate 			 */
6670Sstevel@tonic-gate 			pd->fpclass = fp_subnormal;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 	} else if ((kluge->f.significand & 0x80000000) == 0) {
6700Sstevel@tonic-gate 		/*
6710Sstevel@tonic-gate 		 * In Intel's extended format, if the exponent is
6720Sstevel@tonic-gate 		 * nonzero but the explicit integer bit is zero, this
6730Sstevel@tonic-gate 		 * is an "unsupported format" bit pattern; treat it
6740Sstevel@tonic-gate 		 * like a signaling NaN.
6750Sstevel@tonic-gate 		 */
6760Sstevel@tonic-gate 		pd->fpclass = fp_signaling;
6770Sstevel@tonic-gate 		*ps = 0;
6780Sstevel@tonic-gate 		return;
6790Sstevel@tonic-gate 	} else if (kluge->f.msw.exponent == 0x7fff) {	/* inf or nan */
6800Sstevel@tonic-gate 		if (((kluge->f.significand & 0x7fffffff) |
6810Sstevel@tonic-gate 		    kluge->f.significand2) == 0)
6820Sstevel@tonic-gate 			pd->fpclass = fp_infinity;
6830Sstevel@tonic-gate 		else if ((kluge->f.significand & 0x7fffffff) >= 0x40000000)
6840Sstevel@tonic-gate 			pd->fpclass = fp_quiet;
6850Sstevel@tonic-gate 		else
6860Sstevel@tonic-gate 			pd->fpclass = fp_signaling;
6870Sstevel@tonic-gate 		*ps = 0;
6880Sstevel@tonic-gate 		return;
6890Sstevel@tonic-gate 	} else {
6900Sstevel@tonic-gate 		pd->fpclass = fp_normal;
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	ef = 0;
6940Sstevel@tonic-gate 	__extended_to_bigfloat(px, &bf);
6950Sstevel@tonic-gate 	__bigfloat_to_decimal(&bf, pm, pd, &ef);
6960Sstevel@tonic-gate 	if (ef != 0)
6970Sstevel@tonic-gate 		__base_conversion_set_exception(ef);
6980Sstevel@tonic-gate 	*ps = ef;
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate void
quadruple_to_decimal(quadruple * px,decimal_mode * pm,decimal_record * pd,fp_exception_field_type * ps)7020Sstevel@tonic-gate quadruple_to_decimal(quadruple *px, decimal_mode *pm, decimal_record *pd,
7030Sstevel@tonic-gate     fp_exception_field_type *ps)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	quadruple_equivalence	*kluge;
7060Sstevel@tonic-gate 	_big_float		bf;
7070Sstevel@tonic-gate 	fp_exception_field_type	ef;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	kluge = (quadruple_equivalence *)px;
7100Sstevel@tonic-gate 	pd->sign = kluge->f.msw.sign;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	/* decide what to do based on the class of x */
7130Sstevel@tonic-gate 	if (kluge->f.msw.exponent == 0) {	/* 0 or subnormal */
7140Sstevel@tonic-gate 		if (kluge->f.msw.significand == 0 &&
7150Sstevel@tonic-gate 		    (kluge->f.significand2 | kluge->f.significand3 |
7160Sstevel@tonic-gate 		    kluge->f.significand4) == 0) {
7170Sstevel@tonic-gate 			pd->fpclass = fp_zero;
7180Sstevel@tonic-gate 			*ps = 0;
7190Sstevel@tonic-gate 			return;
7200Sstevel@tonic-gate 		} else {
7210Sstevel@tonic-gate 			pd->fpclass = fp_subnormal;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 	} else if (kluge->f.msw.exponent == 0x7fff) {	/* inf or nan */
7240Sstevel@tonic-gate 		if (kluge->f.msw.significand == 0 &&
7250Sstevel@tonic-gate 		    (kluge->f.significand2 | kluge->f.significand3 |
7260Sstevel@tonic-gate 		    kluge->f.significand4) == 0)
7270Sstevel@tonic-gate 			pd->fpclass = fp_infinity;
7280Sstevel@tonic-gate 		else if (kluge->f.msw.significand >= 0x8000)
7290Sstevel@tonic-gate 			pd->fpclass = fp_quiet;
7300Sstevel@tonic-gate 		else
7310Sstevel@tonic-gate 			pd->fpclass = fp_signaling;
7320Sstevel@tonic-gate 		*ps = 0;
7330Sstevel@tonic-gate 		return;
7340Sstevel@tonic-gate 	} else {
7350Sstevel@tonic-gate 		pd->fpclass = fp_normal;
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	ef = 0;
7390Sstevel@tonic-gate 	__quadruple_to_bigfloat(px, &bf);
7400Sstevel@tonic-gate 	__bigfloat_to_decimal(&bf, pm, pd, &ef);
7410Sstevel@tonic-gate 	if (ef != 0)
7420Sstevel@tonic-gate 		__base_conversion_set_exception(ef);
7430Sstevel@tonic-gate 	*ps = ef;
7440Sstevel@tonic-gate }
745