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