📄 double_decim.c
字号:
#if !defined(lint) && defined(SCCSIDS)static char sccsid[] = "@(#)double_decim.c 1.1 92/07/30 SMI";#endif/* * Copyright (c) 1988 by Sun Microsystems, Inc. *//* Conversion between binary and decimal floating point. */#include "base_conversion.h"/* PRIVATE FUNCTIONS */voiddecimal_round(pm, pd, ps, round, sticky) decimal_mode *pm; decimal_record *pd; fp_exception_field_type *ps; char round; unsigned sticky;/* * Rounds decimal record *pd according to modes in *pm, recording exceptions * for inexact or overflow in *ps. round is the round digit and sticky is 0 * or non-zero to indicate exact or inexact. pd->ndigits is expected to be * correctly set. */{ int lsd, i; if ((round == '0') && (sticky == 0)) { /* Exact. */ goto done; } *ps |= 1 << fp_inexact; switch (pm->rd) { case fp_nearest: if (round < '5') goto done; if (round > '5') goto roundup; if (sticky != 0) goto roundup; /* Now in ambiguous case; round up if lsd is odd. */ if (pd->ndigits <= 0) goto done; /* Presumed 0. */ lsd = pd->ds[pd->ndigits - 1] - '0'; if ((lsd % 2) == 0) goto done; goto roundup; case fp_positive: if (pd->sign != 0) goto done; goto roundup; case fp_negative: if (pd->sign == 0) goto done; goto roundup; case fp_tozero: goto done; }roundup: for (i = (pd->ndigits - 1); (pd->ds[i] == '9') && (i >= 0); i--) pd->ds[i] = '0'; if (i >= 0) (pd->ds[i])++; else { /* Rounding carry out has occurred. */ pd->ds[0] = '1'; if (pm->df == floating_form) { /* For E format, simply * adjust exponent. */ pd->exponent++; } else { /* For F format, increase length of string. */ if (pd->ndigits > 0) pd->ds[pd->ndigits] = '0'; pd->ndigits++; } } goto ret;done: if (pd->ndigits <= 0) { /* Create zero string. */ pd->ds[0] = '0'; pd->ndigits = 1; }ret: pd->ds[pd->ndigits] = 0;/* Terminate string. */ return;}voidbinary_to_decimal_integer(pu, nsig, ds, nzeros, ndigs) unpacked *pu; /* Input unpacked integer value input. */ unsigned nsig; /* Input number of significant digits * required. */ char ds[]; /* Output decimal integer string output - * must be large enough. */unsigned *nzeros; /* Output number of implicit trailing zeros * produced. */unsigned *ndigs; /* Output number of explicit digits produced * in ds. *//* * Converts an unpacked integer value *pu into a decimal string in *ds, of * length returned in *ndigs. /* Inexactness is indicated by setting * ds[ndigs-1] odd. */{ _big_float *pd, b, d; int e, i, is; _BIG_FLOAT_DIGIT stickyshift; char s[4]; b.bsize = _BIG_FLOAT_SIZE; /* Initialize sizes of big floats. */ d.bsize = _BIG_FLOAT_SIZE; _unpacked_to_big_float(pu, &b, &e); if (e < 0) { _right_shift_base_two(&b, (short unsigned) -e, &stickyshift);#ifdef DEBUG assert(stickyshift == 0);#endif } _big_binary_to_big_decimal(&b, &d); if (e <= 0) pd = &d; else { _big_float_times_power(&d, 2, e, (int) nsig, &pd); switch (pd) { case BIG_FLOAT_TIMES_TOOBIG: { char bcastring[80]; (void) sprintf(bcastring, " binary exponent %d ", e); _base_conversion_abort(ERANGE, bcastring); break; } case BIG_FLOAT_TIMES_NOMEM: { char bcastring[80]; (void) sprintf(bcastring, " binary exponent %d ", e); _base_conversion_abort(ENOMEM, bcastring); break; } default:#ifdef DEBUG if (pd != &d) (void) printf(" large binary exponent %d needs heap buffer \n", e); printf(" product "); _display_big_float(pd, 10);#endif break; } } _fourdigitsquick((short unsigned) pd->bsignificand[pd->blength - 1], s); for (i = 0; s[i] == '0'; i++); /* Find first non-zero digit. */ for (is = 0; i <= 3;) ds[is++] = s[i++]; /* Copy subsequent digits. */ for (i = (pd->blength - 2); i >= 0; i--) { /* Convert powers of * 10**4 to decimal * digits. */ _fourdigitsquick((short unsigned) pd->bsignificand[i], &(ds[is])); is += 4; } ds[is] = 0; *ndigs = is; *nzeros = pd->bexponent; if (pd != &d) _free_big_float(pd);#ifdef DEBUG printf(" binary to decimal integer result %s * 10**%d \n", ds, *nzeros);#endif}voidbinary_to_decimal_fraction(pu, nsig, nfrac, ds, nzeros, ndigs) unpacked *pu; /* Input unpacked fraction value output < 1 * in magnitude. */ unsigned nsig; /* Input number of significant digits * required. */ unsigned nfrac; /* Input number of digits after point * required. */ char ds[]; /* Output decimal integer string output - * must be large enough. */int *nzeros; /* Output number of implicit leading zeros * produced. */int *ndigs; /* Output number of explicit digits produced * in ds. *//* * Converts an unpacked fraction value *pu into a decimal string consisting * of a) an implicit '.' b) *nzeros implicit leading zeros c) *ndigs explicit * digits in ds ds contains at least nsig significant digits. nzeros + * * *ndigs is at least nfrac digits after the point. Inexactness is indicated * by sticking to the lsb. */{ _big_float *pb, b, d; int e, i, j, is, excess; char s[4]; int tensig, tenpower; _BIG_FLOAT_DIGIT stickyshift; *nzeros = 0; if (pu->fpclass == fp_zero) { /* Exact zero. */ for (i = 0; i <= nfrac; i++) ds[i] = '0'; for (; i <= nsig; i++) ds[i] = '0'; *ndigs = i; return; } b.bsize = _BIG_FLOAT_SIZE; /* Initialize sizes of big floats. */ d.bsize = _BIG_FLOAT_SIZE; _unpacked_to_big_float(pu, &b, &e); /* * e < 0 always */ b.bexponent = e; tenpower = nsig + (int) (((17 - e - 16 * b.blength) * (unsigned long) 19729) >> 16); if (tenpower < nfrac) tenpower = nfrac; tensig = nfrac; if (nsig > tensig) tensig = nsig; tensig = 1 + (((tensig + 2) * 217706) >> 16); tensig = -tensig;#ifdef DEBUG printf(" binary to decimal fraction exponent 2**%d \n", e); printf(" binary to decimal fraction nsig %d nfrac %d tenpower %d tensig %d \n", nsig, nfrac, tenpower, tensig);#endif _big_float_times_power(&b, 10, tenpower, tensig, &pb); switch (pb) { case BIG_FLOAT_TIMES_TOOBIG: { char bcastring[80]; (void) sprintf(bcastring, " decimal exponent %d ", tenpower); _base_conversion_abort(ERANGE, bcastring); break; } case BIG_FLOAT_TIMES_NOMEM: { char bcastring[80]; (void) sprintf(bcastring, " decimal exponent %d ", tenpower); _base_conversion_abort(ENOMEM, bcastring); break; } default:#ifdef DEBUG if (pb != &b) printf(" large decimal exponent %d needs heap buffer \n", tenpower); printf(" product "); _display_big_float(pb, 2);#endif break; } if (pb->bexponent <= -16) { /* Have computed appropriate decimal part; now toss fraction. */ excess = (-pb->bexponent) / 16;#ifdef DEBUG printf(" discard %d excess fraction bits \n", 16 * excess);#endif for (i = 0; (i < excess) && (pb->bsignificand[i] == 0); i++); if (i < excess) pb->bsignificand[excess] |= 1; /* Sticky bit for * discarded fraction. */ for (i = excess; i < pb->blength; i++) pb->bsignificand[i - excess] = pb->bsignificand[i]; pb->blength -= excess; pb->bexponent += 16 * excess; } if (pb->bexponent < 0) { _right_shift_base_two(pb, (short unsigned) -pb->bexponent, &stickyshift); if (stickyshift != 0) pb->bsignificand[0] |= 1; /* Stick to lsb. */ } _big_binary_to_big_decimal(pb, &d); i = d.blength - 1; while (d.bsignificand[i] == 0) i--; _fourdigitsquick((short unsigned) d.bsignificand[i], s); for (j = 0; s[j] == '0'; j++); /* Find first non-zero digit. */ for (is = 0; j <= 3;) ds[is++] = s[j++]; /* Copy subsequent digits. */ for (i--; i >= 0; i--) {/* Convert powers of 10**4 to decimal digits. */ _fourdigitsquick((short unsigned) d.bsignificand[i], &(ds[is])); is += 4; } ds[is] = 0; *ndigs = is;#ifdef DEBUG assert(tenpower >= is);#endif *nzeros = tenpower - is;/* There were supposed to be tenpower leading * digits, and is were found. */ if (pb != &b) _free_big_float(pb);#ifdef DEBUG printf(" binary to decimal fraction result .%s * 10**%d \n", ds, -(*nzeros));#endif}void_unpacked_to_decimal(px, pm, pd, ps) unpacked *px; decimal_mode *pm; decimal_record *pd; fp_exception_field_type *ps;{ unpacked fx, ix; unsigned fmask, imask; int i, intdigs, fracdigs, fraczeros, fracsigs, ids, idsbound, lzbound; unsigned nsig, nfrac, intzeros, intsigs; char is[_INTEGER_SIZE], fs[DECIMAL_STRING_LENGTH]; char round = '0'; unsigned sticky = 0; pd->sign = px->sign; pd->fpclass = px->fpclass; if ((px->fpclass != fp_normal) && (px->fpclass != fp_subnormal)) return; if ((pm->ndigits >= DECIMAL_STRING_LENGTH) || ((pm->df == floating_form) && (pm->ndigits < 1))) { /* Gross overflow or bad * spec. */overflow: *ps |= 1 << fp_overflow; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -