xref: /illumos-gate/usr/src/lib/libc/port/fp/aconvert.c (revision 146fa2c5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57257d1b4Sraf  * Common Development and Distribution License (the "License").
67257d1b4Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277257d1b4Sraf #include "lint.h"
287c478bd9Sstevel@tonic-gate #include "base_conversion.h"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* translation table from hex values to hex chars */
317c478bd9Sstevel@tonic-gate static const char *hexchar = "0123456789abcdef";
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * Convert arg to a hexadecimal string.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * If arg is finite and nonzero, buf is filled with ndigits hexadecimal
377c478bd9Sstevel@tonic-gate  * digits, representing the significand of arg, followed by a null byte
387c478bd9Sstevel@tonic-gate  * (so ndigits must be at least 1 and buf must be large enough to hold
397c478bd9Sstevel@tonic-gate  * ndigits + 1 characters).  If ndigits is large enough, the representa-
407c478bd9Sstevel@tonic-gate  * tion is exact; otherwise, the value is rounded according to the pre-
417c478bd9Sstevel@tonic-gate  * vailing rounding mode to fit the requested number of digits.  Either
427c478bd9Sstevel@tonic-gate  * way, the result is normalized so that the first digit is '1'.  The
437c478bd9Sstevel@tonic-gate  * corresponding base two exponent is passed back in *exp.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * If arg is zero, buf is filled with ndigits zeros followed by a null,
467c478bd9Sstevel@tonic-gate  * and *exp is set to zero.  If arg is infinite or NaN, __infnanstring
477c478bd9Sstevel@tonic-gate  * is called to place an appropriate string in buf, and *exp is set to
487c478bd9Sstevel@tonic-gate  * zero.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * Regardless of the value of arg, its sign bit is stored in *sign.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #if defined(__sparc)
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate void
__aconvert(double arg,int ndigits,int * exp,int * sign,char * buf)567c478bd9Sstevel@tonic-gate __aconvert(double arg, int ndigits, int *exp, int *sign, char *buf)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 	union {
597c478bd9Sstevel@tonic-gate 		unsigned int	i[2];
607c478bd9Sstevel@tonic-gate 		long long	l;
617c478bd9Sstevel@tonic-gate 		double		d;
627c478bd9Sstevel@tonic-gate 	} a, c;
637c478bd9Sstevel@tonic-gate 	int		ha, i, s;
647c478bd9Sstevel@tonic-gate 	unsigned int	d;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	a.d = arg;
677c478bd9Sstevel@tonic-gate 	*sign = s = a.i[0] >> 31;
687c478bd9Sstevel@tonic-gate 	ha = a.i[0] & ~0x80000000;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	/* check for infinity or nan */
717c478bd9Sstevel@tonic-gate 	if (ha >= 0x7ff00000) {
727c478bd9Sstevel@tonic-gate 		*exp = 0;
737c478bd9Sstevel@tonic-gate 		__infnanstring((ha == 0x7ff00000 && a.i[1] == 0)?
747c478bd9Sstevel@tonic-gate 		    fp_infinity : fp_quiet, ndigits, buf);
757c478bd9Sstevel@tonic-gate 		return;
767c478bd9Sstevel@tonic-gate 	}
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	/* check for subnormal or zero */
797c478bd9Sstevel@tonic-gate 	if (ha < 0x00100000) {
807c478bd9Sstevel@tonic-gate 		if ((ha | a.i[1]) == 0) {
817c478bd9Sstevel@tonic-gate 			*exp = 0;
827c478bd9Sstevel@tonic-gate 			for (i = 0; i < ndigits; i++)
837c478bd9Sstevel@tonic-gate 				buf[i] = '0';
847c478bd9Sstevel@tonic-gate 			buf[ndigits] = '\0';
857c478bd9Sstevel@tonic-gate 			return;
867c478bd9Sstevel@tonic-gate 		}
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 		/*
897c478bd9Sstevel@tonic-gate 		 * Normalize.  It would be much simpler if we could just
907c478bd9Sstevel@tonic-gate 		 * multiply by a power of two here, but some SPARC imple-
917c478bd9Sstevel@tonic-gate 		 * mentations would flush the subnormal operand to zero
927c478bd9Sstevel@tonic-gate 		 * when nonstandard mode is enabled.
937c478bd9Sstevel@tonic-gate 		 */
947c478bd9Sstevel@tonic-gate 		a.i[0] = ha;
957c478bd9Sstevel@tonic-gate 		a.d = (double)a.l;
967c478bd9Sstevel@tonic-gate 		if (s)
977c478bd9Sstevel@tonic-gate 			a.d = -a.d;
987c478bd9Sstevel@tonic-gate 		ha = a.i[0] & ~0x80000000;
997c478bd9Sstevel@tonic-gate 		*exp = (ha >> 20) - 0x3ff - 1074;
1007c478bd9Sstevel@tonic-gate 	} else {
1017c478bd9Sstevel@tonic-gate 		*exp = (ha >> 20) - 0x3ff;
1027c478bd9Sstevel@tonic-gate 	}
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	if (ndigits < 14) {
1057c478bd9Sstevel@tonic-gate 		/*
1067c478bd9Sstevel@tonic-gate 		 * Round the significand at the appropriate bit by adding
1077c478bd9Sstevel@tonic-gate 		 * and subtracting a power of two.  This will also raise
1087c478bd9Sstevel@tonic-gate 		 * the inexact exception if anything is rounded off.
1097c478bd9Sstevel@tonic-gate 		 */
1107c478bd9Sstevel@tonic-gate 		c.i[0] = (0x43700000 | (s << 31)) - (ndigits << 22);
1117c478bd9Sstevel@tonic-gate 		c.i[1] = 0;
1127c478bd9Sstevel@tonic-gate 		a.i[0] = (a.i[0] & 0x800fffff) | 0x3ff00000;
1137c478bd9Sstevel@tonic-gate 		a.d = (a.d + c.d) - c.d;
1147c478bd9Sstevel@tonic-gate 		ha = a.i[0] & ~0x80000000;
1157c478bd9Sstevel@tonic-gate 		if (ha >= 0x40000000)
1167c478bd9Sstevel@tonic-gate 			(*exp)++;
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/* convert to hex digits */
1207c478bd9Sstevel@tonic-gate 	buf[0] = '1';
1217c478bd9Sstevel@tonic-gate 	d = ha << 12;
1227c478bd9Sstevel@tonic-gate 	for (i = 1; i < ndigits && i < 6; i++) {
1237c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
1247c478bd9Sstevel@tonic-gate 		d <<= 4;
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 	d = a.i[1];
1277c478bd9Sstevel@tonic-gate 	for (; i < ndigits && i < 14; i++) {
1287c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
1297c478bd9Sstevel@tonic-gate 		d <<= 4;
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 	for (; i < ndigits; i++)
1327c478bd9Sstevel@tonic-gate 		buf[i] = '0';
1337c478bd9Sstevel@tonic-gate 	buf[ndigits] = '\0';
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate void
__qaconvert(long double * arg,int ndigits,int * exp,int * sign,char * buf)1377c478bd9Sstevel@tonic-gate __qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	union {
1407c478bd9Sstevel@tonic-gate 		unsigned int	i[4];
1417c478bd9Sstevel@tonic-gate 		long double	q;
1427c478bd9Sstevel@tonic-gate 	} a;
1437c478bd9Sstevel@tonic-gate 	enum fp_direction_type	rd;
1447c478bd9Sstevel@tonic-gate 	int			ha, i, s;
1457c478bd9Sstevel@tonic-gate 	unsigned int		b, r, d;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	a.q = *arg;
1487c478bd9Sstevel@tonic-gate 	*sign = a.i[0] >> 31;
149*146fa2c5SDouglas Priest 	ha = a.i[0] &= ~0x80000000;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/* check for infinity or nan */
1527c478bd9Sstevel@tonic-gate 	if (ha >= 0x7fff0000) {
1537c478bd9Sstevel@tonic-gate 		*exp = 0;
1547c478bd9Sstevel@tonic-gate 		__infnanstring((ha == 0x7fff0000 && (a.i[1] | a.i[2] | a.i[3])
1557c478bd9Sstevel@tonic-gate 		    == 0)? fp_infinity : fp_quiet, ndigits, buf);
1567c478bd9Sstevel@tonic-gate 		return;
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* check for subnormal or zero */
1607c478bd9Sstevel@tonic-gate 	if (ha < 0x00010000) {
1617c478bd9Sstevel@tonic-gate 		if ((ha | a.i[1] | a.i[2] | a.i[3]) == 0) {
1627c478bd9Sstevel@tonic-gate 			*exp = 0;
1637c478bd9Sstevel@tonic-gate 			for (i = 0; i < ndigits; i++)
1647c478bd9Sstevel@tonic-gate 				buf[i] = '0';
1657c478bd9Sstevel@tonic-gate 			buf[ndigits] = '\0';
1667c478bd9Sstevel@tonic-gate 			return;
1677c478bd9Sstevel@tonic-gate 		}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 		/* normalize */
1707c478bd9Sstevel@tonic-gate 		i = 0;
1717c478bd9Sstevel@tonic-gate 		while ((a.i[0] | (a.i[1] & 0xffff0000)) == 0) {
1727c478bd9Sstevel@tonic-gate 			a.i[0] = a.i[1];
1737c478bd9Sstevel@tonic-gate 			a.i[1] = a.i[2];
1747c478bd9Sstevel@tonic-gate 			a.i[2] = a.i[3];
1757c478bd9Sstevel@tonic-gate 			a.i[3] = 0;
1767c478bd9Sstevel@tonic-gate 			i += 32;
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 		while ((a.i[0] & 0x7fff0000) == 0) {
1797c478bd9Sstevel@tonic-gate 			a.i[0] = (a.i[0] << 1) | (a.i[1] >> 31);
1807c478bd9Sstevel@tonic-gate 			a.i[1] = (a.i[1] << 1) | (a.i[2] >> 31);
1817c478bd9Sstevel@tonic-gate 			a.i[2] = (a.i[2] << 1) | (a.i[3] >> 31);
1827c478bd9Sstevel@tonic-gate 			a.i[3] <<= 1;
1837c478bd9Sstevel@tonic-gate 			i++;
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 		*exp = -0x3ffe - i;
1867c478bd9Sstevel@tonic-gate 	} else {
1877c478bd9Sstevel@tonic-gate 		*exp = (ha >> 16) - 0x3fff;
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if (ndigits < 29) {
1917c478bd9Sstevel@tonic-gate 		/*
1927c478bd9Sstevel@tonic-gate 		 * Round the significand at the appropriate bit using
1937c478bd9Sstevel@tonic-gate 		 * integer arithmetic.  Explicitly raise the inexact
1947c478bd9Sstevel@tonic-gate 		 * exception if anything is rounded off.
1957c478bd9Sstevel@tonic-gate 		 */
196*146fa2c5SDouglas Priest 		a.i[0] = (a.i[0] & 0xffff) | 0x10000;
1977c478bd9Sstevel@tonic-gate 		if (ndigits <= 5) {
1987c478bd9Sstevel@tonic-gate 			/*
1997c478bd9Sstevel@tonic-gate 			 * i and b are the index and bit position in a.i[]
2007c478bd9Sstevel@tonic-gate 			 * of the last bit to be retained.  r holds the bits
2017c478bd9Sstevel@tonic-gate 			 * to be rounded off, left-adjusted and sticky.
2027c478bd9Sstevel@tonic-gate 			 */
2037c478bd9Sstevel@tonic-gate 			i = 0;
2047c478bd9Sstevel@tonic-gate 			s = (5 - ndigits) << 2;
2057c478bd9Sstevel@tonic-gate 			b = 1 << s;
2067c478bd9Sstevel@tonic-gate 			r = ((a.i[0] << 1) << (31 - s)) | (a.i[1] >> s);
2077c478bd9Sstevel@tonic-gate 			if ((a.i[1] & (b - 1)) | a.i[2] | a.i[3])
2087c478bd9Sstevel@tonic-gate 				r |= 1;
2097c478bd9Sstevel@tonic-gate 			a.i[0] &= ~(b - 1);
2107c478bd9Sstevel@tonic-gate 			a.i[1] = a.i[2] = a.i[3] = 0;
2117c478bd9Sstevel@tonic-gate 		} else if (ndigits <= 13) {
2127c478bd9Sstevel@tonic-gate 			i = 1;
2137c478bd9Sstevel@tonic-gate 			s = (13 - ndigits) << 2;
2147c478bd9Sstevel@tonic-gate 			b = 1 << s;
2157c478bd9Sstevel@tonic-gate 			r = ((a.i[1] << 1) << (31 - s)) | (a.i[2] >> s);
2167c478bd9Sstevel@tonic-gate 			if ((a.i[2] & (b - 1)) | a.i[3])
2177c478bd9Sstevel@tonic-gate 				r |= 1;
2187c478bd9Sstevel@tonic-gate 			a.i[1] &= ~(b - 1);
2197c478bd9Sstevel@tonic-gate 			a.i[2] = a.i[3] = 0;
2207c478bd9Sstevel@tonic-gate 		} else if (ndigits <= 21) {
2217c478bd9Sstevel@tonic-gate 			i = 2;
2227c478bd9Sstevel@tonic-gate 			s = (21 - ndigits) << 2;
2237c478bd9Sstevel@tonic-gate 			b = 1 << s;
2247c478bd9Sstevel@tonic-gate 			r = ((a.i[2] << 1) << (31 - s)) | (a.i[3] >> s);
2257c478bd9Sstevel@tonic-gate 			if (a.i[3] & (b - 1))
2267c478bd9Sstevel@tonic-gate 				r |= 1;
2277c478bd9Sstevel@tonic-gate 			a.i[2] &= ~(b - 1);
2287c478bd9Sstevel@tonic-gate 			a.i[3] = 0;
2297c478bd9Sstevel@tonic-gate 		} else {
2307c478bd9Sstevel@tonic-gate 			i = 3;
2317c478bd9Sstevel@tonic-gate 			s = (29 - ndigits) << 2;
2327c478bd9Sstevel@tonic-gate 			b = 1 << s;
2337c478bd9Sstevel@tonic-gate 			r = (a.i[3] << 1) << (31 - s);
2347c478bd9Sstevel@tonic-gate 			a.i[3] &= ~(b - 1);
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 		/* conversion is inexact if r is not zero */
2387c478bd9Sstevel@tonic-gate 		if (r) {
2397c478bd9Sstevel@tonic-gate 			__base_conversion_set_exception(
2407c478bd9Sstevel@tonic-gate 			    (fp_exception_field_type)(1 << fp_inexact));
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 			/* massage the rounding direction based on the sign */
2437c478bd9Sstevel@tonic-gate 			rd = _QgetRD();
2447c478bd9Sstevel@tonic-gate 			if (*sign && (rd == fp_positive || rd == fp_negative))
2457c478bd9Sstevel@tonic-gate 				rd = fp_positive + fp_negative - rd;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 			/* decide whether to round up */
2487c478bd9Sstevel@tonic-gate 			if (rd == fp_positive || (rd == fp_nearest &&
2497c478bd9Sstevel@tonic-gate 			    (r > 0x80000000u || (r == 0x80000000u &&
2507c478bd9Sstevel@tonic-gate 			    (a.i[i] & b))))) {
2517c478bd9Sstevel@tonic-gate 				a.i[i] += b;
2527c478bd9Sstevel@tonic-gate 				while (a.i[i] == 0)
2537c478bd9Sstevel@tonic-gate 					a.i[--i]++;
254*146fa2c5SDouglas Priest 				if (a.i[0] >= 0x20000)
2557c478bd9Sstevel@tonic-gate 					(*exp)++;
2567c478bd9Sstevel@tonic-gate 			}
2577c478bd9Sstevel@tonic-gate 		}
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/* convert to hex digits */
2617c478bd9Sstevel@tonic-gate 	buf[0] = '1';
2627c478bd9Sstevel@tonic-gate 	d = a.i[0] << 16;
2637c478bd9Sstevel@tonic-gate 	for (i = 1; i < ndigits && i < 5; i++) {
2647c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
2657c478bd9Sstevel@tonic-gate 		d <<= 4;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 	d = a.i[1];
2687c478bd9Sstevel@tonic-gate 	for (; i < ndigits && i < 13; i++) {
2697c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
2707c478bd9Sstevel@tonic-gate 		d <<= 4;
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 	d = a.i[2];
2737c478bd9Sstevel@tonic-gate 	for (; i < ndigits && i < 21; i++) {
2747c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
2757c478bd9Sstevel@tonic-gate 		d <<= 4;
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 	d = a.i[3];
2787c478bd9Sstevel@tonic-gate 	for (; i < ndigits && i < 29; i++) {
2797c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
2807c478bd9Sstevel@tonic-gate 		d <<= 4;
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	for (; i < ndigits; i++)
2837c478bd9Sstevel@tonic-gate 		buf[i] = '0';
2847c478bd9Sstevel@tonic-gate 	buf[ndigits] = '\0';
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64)
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate /*
2907c478bd9Sstevel@tonic-gate  * The following code assumes the rounding precision mode is set
2917c478bd9Sstevel@tonic-gate  * to the default (round to 64 bits).
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate void
__qaconvert(long double * arg,int ndigits,int * exp,int * sign,char * buf)2947c478bd9Sstevel@tonic-gate __qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	union {
2977c478bd9Sstevel@tonic-gate 		unsigned int	i[3];
2987c478bd9Sstevel@tonic-gate 		long double	x;
2997c478bd9Sstevel@tonic-gate 	} a, c;
3007c478bd9Sstevel@tonic-gate 	int		ea, i, s;
3017c478bd9Sstevel@tonic-gate 	unsigned int	d;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	a.x = *arg;
3047c478bd9Sstevel@tonic-gate 	*sign = s = (a.i[2] >> 15) & 1;
3057c478bd9Sstevel@tonic-gate 	ea = a.i[2] & 0x7fff;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* check for infinity or nan */
3087c478bd9Sstevel@tonic-gate 	if (ea == 0x7fff) {
3097c478bd9Sstevel@tonic-gate 		*exp = 0;
3107c478bd9Sstevel@tonic-gate 		__infnanstring((((a.i[1] << 1) | a.i[0]) == 0)?
3117c478bd9Sstevel@tonic-gate 		    fp_infinity : fp_quiet, ndigits, buf);
3127c478bd9Sstevel@tonic-gate 		return;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* check for subnormal or zero */
3167c478bd9Sstevel@tonic-gate 	if (ea == 0) {
3177c478bd9Sstevel@tonic-gate 		if ((a.i[1] | a.i[0]) == 0) {
3187c478bd9Sstevel@tonic-gate 			*exp = 0;
3197c478bd9Sstevel@tonic-gate 			for (i = 0; i < ndigits; i++)
3207c478bd9Sstevel@tonic-gate 				buf[i] = '0';
3217c478bd9Sstevel@tonic-gate 			buf[ndigits] = '\0';
3227c478bd9Sstevel@tonic-gate 			return;
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		/* normalize */
3267c478bd9Sstevel@tonic-gate 		a.x *= 18446744073709551616.0; /* 2^64 */
3277c478bd9Sstevel@tonic-gate 		ea = a.i[2] & 0x7fff;
3287c478bd9Sstevel@tonic-gate 		*exp = ea - 0x403f;
3297c478bd9Sstevel@tonic-gate 	} else {
3307c478bd9Sstevel@tonic-gate 		*exp = ea - 0x3fff;
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (ndigits < 17) {
3347c478bd9Sstevel@tonic-gate 		/*
3357c478bd9Sstevel@tonic-gate 		 * Round the significand at the appropriate bit by adding
3367c478bd9Sstevel@tonic-gate 		 * and subtracting a power of two.  This will also raise
3377c478bd9Sstevel@tonic-gate 		 * the inexact exception if anything is rounded off.
3387c478bd9Sstevel@tonic-gate 		 */
3397c478bd9Sstevel@tonic-gate 		c.i[2] = (0x4042 | (s << 15)) - (ndigits << 2);
3407c478bd9Sstevel@tonic-gate 		c.i[1] = 0x80000000;
3417c478bd9Sstevel@tonic-gate 		c.i[0] = 0;
3427c478bd9Sstevel@tonic-gate 		a.i[2] = 0x3fff | (s << 15);
3437c478bd9Sstevel@tonic-gate 		a.x = (a.x + c.x) - c.x;
3447c478bd9Sstevel@tonic-gate 		ea = a.i[2] & 0x7fff;
3457c478bd9Sstevel@tonic-gate 		if (ea >= 0x4000)
3467c478bd9Sstevel@tonic-gate 			(*exp)++;
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/* convert to hex digits */
3507c478bd9Sstevel@tonic-gate 	buf[0] = '1';
3517c478bd9Sstevel@tonic-gate 	d = (a.i[1] << 1) | (a.i[0] >> 31);
3527c478bd9Sstevel@tonic-gate 	for (i = 1; i < ndigits && i < 9; i++) {
3537c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
3547c478bd9Sstevel@tonic-gate 		d <<= 4;
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	d = a.i[0] << 1;
3577c478bd9Sstevel@tonic-gate 	for (; i < ndigits && i < 17; i++) {
3587c478bd9Sstevel@tonic-gate 		buf[i] = hexchar[d >> 28];
3597c478bd9Sstevel@tonic-gate 		d <<= 4;
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 	for (; i < ndigits; i++)
3627c478bd9Sstevel@tonic-gate 		buf[i] = '0';
3637c478bd9Sstevel@tonic-gate 	buf[ndigits] = '\0';
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate void
__aconvert(double arg,int ndigits,int * exp,int * sign,char * buf)3677c478bd9Sstevel@tonic-gate __aconvert(double arg, int ndigits, int *exp, int *sign, char *buf)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	union {
3707c478bd9Sstevel@tonic-gate 		int	i[2];
3717c478bd9Sstevel@tonic-gate 		double	d;
3727c478bd9Sstevel@tonic-gate 	} a;
3737c478bd9Sstevel@tonic-gate 	long double	ldarg;
3747c478bd9Sstevel@tonic-gate 	int		ha;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/* avoid raising invalid operation exception for signaling nan */
3777c478bd9Sstevel@tonic-gate 	a.i[0] = *(int *)&arg;
3787c478bd9Sstevel@tonic-gate 	a.i[1] = *(1+(int *)&arg);
3797c478bd9Sstevel@tonic-gate 	ha = a.i[1] & ~0x80000000;
3807c478bd9Sstevel@tonic-gate 	if (ha > 0x7ff00000 || (ha == 0x7ff00000 && a.i[0] != 0))
3817c478bd9Sstevel@tonic-gate 		a.i[1] |= 0x80000; /* make nan quiet */
3827c478bd9Sstevel@tonic-gate 	ldarg = a.d;
3837c478bd9Sstevel@tonic-gate 	__qaconvert(&ldarg, ndigits, exp, sign, buf);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate #else
3877c478bd9Sstevel@tonic-gate #error Unknown architecture
3887c478bd9Sstevel@tonic-gate #endif
389