📄 decimal_bin.c
字号:
#if !defined(lint) && defined(SCCSIDS)static char sccsid[] = "@(#)decimal_bin.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"voiddecimal_to_binary_integer(ds, ndigs, nzeros, nsig, pb) char ds[]; /* Input decimal integer string. */unsigned ndigs; /* Input number of explicit digits in ds. */unsigned nzeros; /* Input number of implicit trailing zeros. */unsigned nsig; /* Input number of significant bits required. */_big_float *pb; /* Pointer to big_float to receive result. *//* * Converts a decimal integer string ds with ndigs explicit leading digits * and nzeros implicit trailing zeros to a _big_float **pb, which only * requires nsig significand bits. *//* Inexactness is indicated by pb->bsignificand[0] |= 1. *//* * If the input is too big for a big_float, pb->bexponent is set to 0x7fff. */{ unsigned nzout; _big_float d, *pbout; d.bsize = _BIG_FLOAT_SIZE; _integerstring_to_big_decimal(ds, ndigs, nzeros, &nzout, &d); _big_decimal_to_big_binary(&d, pb); if (nzout != 0) { _big_float_times_power(pb, 10, (int) nzout, (int) nsig, &pbout); switch (pbout) { case BIG_FLOAT_TIMES_TOOBIG:#ifdef DEBUG (void) printf(" decimal_to_binary_integer: decimal exponent %d too large for tables ", nzout);#endif pb->bexponent = 0x7fff; break; case BIG_FLOAT_TIMES_NOMEM: { char bcastring[80]; (void) sprintf(bcastring, " decimal exponent %d ", nzout); _base_conversion_abort(ENOMEM, bcastring); break; } default:#ifdef DEBUG if (pbout != pb) (void) printf(" decimal_to_binary_integer: large decimal exponent %d needs heap buffer \n", nzout); printf(" decimal_to_binary_integer: product "); _display_big_float(pb, 2);#endif if (pbout != pb) { /* We don't really need such * a large product; the * target can't be more than * a quad! */ int i, allweneed; allweneed = 2 + (nsig + 2) / 16; for (i = 0; i < allweneed; i++) pb->bsignificand[i] = pbout->bsignificand[i + pbout->blength - allweneed]; for (i = 0; (pbout->bsignificand[i] == 0); i++); if (i < (pbout->blength - allweneed)) pb->bsignificand[0] |= 1; /* Stick discarded bits. */ pb->blength = allweneed; pb->bexponent = pbout->bexponent + 16 * (pbout->blength - allweneed);#ifdef DEBUG printf(" decimal_to_binary_integer: removed %d excess digits from product \n", pbout->blength - allweneed); _display_big_float(pb, 2);#endif _free_big_float(pbout); } break; } }}voiddecimal_to_binary_fraction(ds, ndigs, nzeros, nsig, pb) char ds[]; /* Decimal integer string input. */unsigned ndigs; /* Number of explicit digits to read. */unsigned nzeros; /* Number of implicit leading zeros before * digits. */unsigned nsig; /* Number of significant bits needed. */_big_float *pb; /* Pointer to intended big_float result. *//* * Converts an explicit decimal string *ds[0]..*ds[ndigs-1] preceded by * nzeros implicit leading zeros after the point into a big_float at *pb. If * the input does not fit exactly in a big_float, the least significant bit * of pbout->significand is stuck on. If the input is too big for the base * conversion tables, pb->bexponent is set to 0x7fff. */{ unsigned twopower, twosig; int i, excess; _big_float d, *pdout; d.bsize = _BIG_FLOAT_SIZE; _fractionstring_to_big_decimal(ds, ndigs, nzeros, &d); twopower = nsig + 3 + (((nzeros + 1) * (unsigned long) 217706) >> 16); twosig = 1 + (((nsig + 2) * (unsigned long) 19729) >> 16);#ifdef DEBUG printf(" decimal_to_binary_fraction sigbits %d twopower %d twosig %d \n", nsig, twopower, twosig);#endif _big_float_times_power(&d, 2, (int) twopower, (int) twosig, &pdout); switch (pdout) { case BIG_FLOAT_TIMES_TOOBIG:#ifdef DEBUG (void) printf(" decimal_to_binary_fraction binary exponent %d too large for tables ", twopower);#endif pb->bexponent = 0x7fff; goto ret; case BIG_FLOAT_TIMES_NOMEM: { char bcastring[80]; (void) sprintf(bcastring, " binary exponent %d ", twopower); _base_conversion_abort(ENOMEM, bcastring); break; } default:#ifdef DEBUG if (&d != pdout) printf(" decimal_to_binary_fraction large binary exponent %d needs heap buffer \n", twopower); printf(" product "); _display_big_float(pdout, 10);#endif break; } if (pdout->bexponent <= -4) { /* Have computed appropriate decimal part; now toss fraction. */ excess = (-pdout->bexponent) / 4;#ifdef DEBUG printf(" discard %d excess fraction digits \n", 4 * excess);#endif for (i = 0; (i < excess) && ((pdout)->bsignificand[i] == 0); i++); if (i < excess) (pdout)->bsignificand[excess] |= 1; /* Sticky bit for * discarded fraction. */ for (i = excess; i < (pdout)->blength; i++) (pdout)->bsignificand[i - excess] = (pdout)->bsignificand[i]; (pdout)->blength -= excess; (pdout)->bexponent += 4 * excess; } _big_decimal_to_big_binary(pdout, pb); if (pdout != &d) _free_big_float(pdout); pb->bexponent = -twopower;ret: return;}voiddecimal_to_unpacked(px, pd, significant_bits) unpacked *px; decimal_record *pd; unsigned significant_bits;/* * Converts *pd to *px so that *px can be correctly rounded. significant_bits * tells how many bits will be significant in the final result to avoid * superfluous computation. Inexactness is communicated by sticking on the * lsb of px->significand[UNPACKED_SIZE-1]. Integer buffer overflow is * indicated with a huge positive exponent. */{ int frac_bits, sigint; unsigned length, ndigs, ntz, nlz, ifrac, nfrac; _big_float bi, bf, *ptounpacked = &bi; px->sign = pd->sign; px->fpclass = pd->fpclass; if ((px->fpclass != fp_normal) && (px->fpclass != fp_subnormal)) goto ret; for (length = 0; pd->ds[length] != 0; length++); if (length == 0) { /* A zero significand slipped by. */ px->fpclass = fp_zero; goto ret; } /* Length contains the number of explicit digits in string. */ if (pd->exponent >= 0) {/* All integer digits. */ ndigs = length; ntz = pd->exponent; /* Trailing zeros. */ ifrac = 0; nfrac = 0; /* No fraction digits. */ nlz = 0; } else if (length <= -pd->exponent) { /* No integer digits. */ ndigs = 0; ntz = 0; ifrac = 0; nfrac = length; nlz = -pd->exponent - length; /* Leading zeros. */ } else { /* Some integer digits, some fraction digits. */ ndigs = length + pd->exponent; ntz = 0; ifrac = ndigs; nfrac = -pd->exponent; nlz = 0; while ((pd->ds[ifrac] == '0') && (nfrac != 0)) { ifrac++; nfrac--; nlz++; } /* Remove leading zeros. */ } if (ndigs != 0) { /* Convert integer digits. */ bi.bsize = _BIG_FLOAT_SIZE; decimal_to_binary_integer(pd->ds, ndigs, ntz, significant_bits, &bi); if (bi.bexponent == 0x7fff) { /* Too big for buffer. */ px->exponent = 0x7fffffff; px->significand[0] = 0x80000000; goto ret; } sigint = 16 * (bi.blength + bi.bexponent - 1); if (sigint < 0) sigint = 0; } else { /* No integer digits. */ bi.blength = 0; bi.bsignificand[0] = 0; bi.bexponent = 0; sigint = 0; } frac_bits = significant_bits - sigint + 2; bf.blength = 0; if ((nfrac != 0) && (frac_bits > 0)) { /* Convert fraction digits, * even if we only need a * round or sticky. */ bf.bsize = _BIG_FLOAT_SIZE; decimal_to_binary_fraction(&(pd->ds[ifrac]), nfrac, nlz, (unsigned) frac_bits, &bf); } else { /* Only need fraction bits for sticky. */ if (nfrac != 0) bi.bsignificand[0] |= 1; /* Stick for fraction. */ } if (bi.blength == 0) { /* No integer digits; all fraction. */ if (bf.bexponent == 0x7fff) { /* Buffer overflowed. */ px->exponent = -0x7fffffff; px->significand[0] = 0x80000000; goto ret; } ptounpacked = &bf; /* Exceptional case - all fraction. */ goto punpack; } if (bf.blength != 0) { /* Combine integer and fraction bits. */ int expdiff = bi.bexponent - (bf.bexponent + 16 * (bf.blength - 1)); /* Exponent difference. */ int uneeded = 2 + (significant_bits + 2) / 16; /* Number of big float * digits needed. */ int nmove, leftshift, i, if0;#ifdef DEBUG printf(" bi+bf exponent diff is %d \n", expdiff); printf(" need %d big float digits \n", uneeded); assert(bi.blength != 0); assert(bf.blength != 0); assert(bi.bsignificand[bi.blength - 1] != 0); /* Normalized bi. */ assert(bf.bsignificand[bf.blength - 1] != 0); /* Normalized bf. */ assert(bi.bexponent >= 0); /* bi is all integer */ assert(((-bf.bexponent - 16 * (bf.blength - 1)) >= 16) || ((bf.bsignificand[bf.blength - 1] >> (-bf.bexponent - 16 * (bf.blength - 1))) == 0)); /* assert either bf << 1 or bf < 1 */ /* * Assert that integer and fraction parts don't overlap by * more than one big digit. */ assert(expdiff > 0); assert(uneeded <= (2 * UNPACKED_SIZE));#endif if (bi.blength >= uneeded) { /* bi will overflow unpacked, * so bf is just a sticky. */ bi.bsignificand[0] |= 1; goto punpack; } leftshift = 16 - (expdiff % 16); if (leftshift > 0) { /* shift bf to align with bi. */ expdiff += 16 * bf.blength; _left_shift_base_two(&bf, (short unsigned) leftshift); expdiff -= 16 * bf.blength; /* If bf.blength is * longer, adjust * expdiff. */ } expdiff += leftshift; expdiff /= 16; /* Remaining expdiff in _BIG_FLOAT_DIGITS. */ expdiff--;#ifdef DEBUG assert(expdiff >= 0); /* expdiff is now equal to the size * of the hole between bi and bf. */#endif nmove = uneeded - bi.blength; /* nmove is the number of words to add to bi. */ if (nmove < 0) nmove = 0; if (nmove > (expdiff + bf.blength)) nmove = (expdiff + bf.blength);#ifdef DEBUG printf(" increase bi by %d words to merge \n", nmove);#endif if (nmove == 0) i = -1; else for (i = (bi.blength - 1 + nmove); i >= nmove; i--) bi.bsignificand[i] = bi.bsignificand[i - nmove]; for (; (i >= 0) && (expdiff > 0); i--) { /* Fill hole with zeros. */ expdiff--; bi.bsignificand[i] = 0; } if0 = i; for (; i >= 0; i--) bi.bsignificand[i] = bf.bsignificand[i + bf.blength - 1 - if0]; for (i = (bf.blength - 2 - if0); bf.bsignificand[i] == 0; i--); /* Find first non-zero. */ if (i >= 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -