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