📄 printf_fp.c
字号:
else if (info->space) outchar (' '); PRINT (special, wspecial, 3); if (info->left && width > 0) PADN (' ', width); return done; } /* We need three multiprecision variables. Now that we have the exponent of the number we can allocate the needed memory. It would be more efficient to use variables of the fixed maximum size but because this would be really big it could lead to memory problems. */ { mp_size_t bignum_size = ((ABS (exponent) + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB + (LDBL_MANT_DIG / BITS_PER_MP_LIMB > 2 ? 8 : 4)) * sizeof (mp_limb_t); frac = (mp_limb_t *) alloca (bignum_size); tmp = (mp_limb_t *) alloca (bignum_size); scale = (mp_limb_t *) alloca (bignum_size); } /* We now have to distinguish between numbers with positive and negative exponents because the method used for the one is not applicable/efficient for the other. */ scalesize = 0; if (exponent > 2) { /* |FP| >= 8.0. */ int scaleexpo = 0; int explog = LDBL_MAX_10_EXP_LOG; int exp10 = 0; const struct mp_power *powers = &_fpioconst_pow10[explog + 1]; int cnt_h, cnt_l, i; if ((exponent + to_shift) % BITS_PER_MP_LIMB == 0) { MPN_COPY_DECR (frac + (exponent + to_shift) / BITS_PER_MP_LIMB, fp_input, fracsize); fracsize += (exponent + to_shift) / BITS_PER_MP_LIMB; } else { cy = __mpn_lshift (frac + (exponent + to_shift) / BITS_PER_MP_LIMB, fp_input, fracsize, (exponent + to_shift) % BITS_PER_MP_LIMB); fracsize += (exponent + to_shift) / BITS_PER_MP_LIMB; if (cy) frac[fracsize++] = cy; } MPN_ZERO (frac, (exponent + to_shift) / BITS_PER_MP_LIMB); assert (powers > &_fpioconst_pow10[0]); do { --powers; /* The number of the product of two binary numbers with n and m bits respectively has m+n or m+n-1 bits. */ if (exponent >= scaleexpo + powers->p_expo - 1) { if (scalesize == 0) {#ifndef __NO_LONG_DOUBLE_MATH if (LDBL_MANT_DIG > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB && info->is_long_double) {#define _FPIO_CONST_SHIFT \ (((LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) \ - _FPIO_CONST_OFFSET) /* 64bit const offset is not enough for IEEE quad long double. */ tmpsize = powers->arraysize + _FPIO_CONST_SHIFT; memcpy (tmp + _FPIO_CONST_SHIFT, &__tens[powers->arrayoff], tmpsize * sizeof (mp_limb_t)); MPN_ZERO (tmp, _FPIO_CONST_SHIFT); /* Adjust exponent, as scaleexpo will be this much bigger too. */ exponent += _FPIO_CONST_SHIFT * BITS_PER_MP_LIMB; } else#endif { tmpsize = powers->arraysize; memcpy (tmp, &__tens[powers->arrayoff], tmpsize * sizeof (mp_limb_t)); } } else { cy = __mpn_mul (tmp, scale, scalesize, &__tens[powers->arrayoff + _FPIO_CONST_OFFSET], powers->arraysize - _FPIO_CONST_OFFSET); tmpsize = scalesize + powers->arraysize - _FPIO_CONST_OFFSET; if (cy == 0) --tmpsize; } if (MPN_GE (frac, tmp)) { int cnt; MPN_ASSIGN (scale, tmp); count_leading_zeros (cnt, scale[scalesize - 1]); scaleexpo = (scalesize - 2) * BITS_PER_MP_LIMB - cnt - 1; exp10 |= 1 << explog; } } --explog; } while (powers > &_fpioconst_pow10[0]); exponent = exp10; /* Optimize number representations. We want to represent the numbers with the lowest number of bytes possible without losing any bytes. Also the highest bit in the scaling factor has to be set (this is a requirement of the MPN division routines). */ if (scalesize > 0) { /* Determine minimum number of zero bits at the end of both numbers. */ for (i = 0; scale[i] == 0 && frac[i] == 0; i++) ; /* Determine number of bits the scaling factor is misplaced. */ count_leading_zeros (cnt_h, scale[scalesize - 1]); if (cnt_h == 0) { /* The highest bit of the scaling factor is already set. So we only have to remove the trailing empty limbs. */ if (i > 0) { MPN_COPY_INCR (scale, scale + i, scalesize - i); scalesize -= i; MPN_COPY_INCR (frac, frac + i, fracsize - i); fracsize -= i; } } else { if (scale[i] != 0) { count_trailing_zeros (cnt_l, scale[i]); if (frac[i] != 0) { int cnt_l2; count_trailing_zeros (cnt_l2, frac[i]); if (cnt_l2 < cnt_l) cnt_l = cnt_l2; } } else count_trailing_zeros (cnt_l, frac[i]); /* Now shift the numbers to their optimal position. */ if (i == 0 && BITS_PER_MP_LIMB - cnt_h > cnt_l) { /* We cannot save any memory. So just roll both numbers so that the scaling factor has its highest bit set. */ (void) __mpn_lshift (scale, scale, scalesize, cnt_h); cy = __mpn_lshift (frac, frac, fracsize, cnt_h); if (cy != 0) frac[fracsize++] = cy; } else if (BITS_PER_MP_LIMB - cnt_h <= cnt_l) { /* We can save memory by removing the trailing zero limbs and by packing the non-zero limbs which gain another free one. */ (void) __mpn_rshift (scale, scale + i, scalesize - i, BITS_PER_MP_LIMB - cnt_h); scalesize -= i + 1; (void) __mpn_rshift (frac, frac + i, fracsize - i, BITS_PER_MP_LIMB - cnt_h); fracsize -= frac[fracsize - i - 1] == 0 ? i + 1 : i; } else { /* We can only save the memory of the limbs which are zero. The non-zero parts occupy the same number of limbs. */ (void) __mpn_rshift (scale, scale + (i - 1), scalesize - (i - 1), BITS_PER_MP_LIMB - cnt_h); scalesize -= i; (void) __mpn_rshift (frac, frac + (i - 1), fracsize - (i - 1), BITS_PER_MP_LIMB - cnt_h); fracsize -= frac[fracsize - (i - 1) - 1] == 0 ? i : i - 1; } } } } else if (exponent < 0) { /* |FP| < 1.0. */ int exp10 = 0; int explog = LDBL_MAX_10_EXP_LOG; const struct mp_power *powers = &_fpioconst_pow10[explog + 1]; mp_size_t used_limbs = fracsize - 1; /* Now shift the input value to its right place. */ cy = __mpn_lshift (frac, fp_input, fracsize, to_shift); frac[fracsize++] = cy; assert (cy == 1 || (frac[fracsize - 2] == 0 && frac[0] == 0)); expsign = 1; exponent = -exponent; assert (powers != &_fpioconst_pow10[0]); do { --powers; if (exponent >= powers->m_expo) { int i, incr, cnt_h, cnt_l; mp_limb_t topval[2]; /* The __mpn_mul function expects the first argument to be bigger than the second. */ if (fracsize < powers->arraysize - _FPIO_CONST_OFFSET) cy = __mpn_mul (tmp, &__tens[powers->arrayoff + _FPIO_CONST_OFFSET], powers->arraysize - _FPIO_CONST_OFFSET, frac, fracsize); else cy = __mpn_mul (tmp, frac, fracsize, &__tens[powers->arrayoff + _FPIO_CONST_OFFSET], powers->arraysize - _FPIO_CONST_OFFSET); tmpsize = fracsize + powers->arraysize - _FPIO_CONST_OFFSET; if (cy == 0) --tmpsize; count_leading_zeros (cnt_h, tmp[tmpsize - 1]); incr = (tmpsize - fracsize) * BITS_PER_MP_LIMB + BITS_PER_MP_LIMB - 1 - cnt_h; assert (incr <= powers->p_expo); /* If we increased the exponent by exactly 3 we have to test for overflow. This is done by comparing with 10 shifted to the right position. */ if (incr == exponent + 3) { if (cnt_h <= BITS_PER_MP_LIMB - 4) { topval[0] = 0; topval[1] = ((mp_limb_t) 10) << (BITS_PER_MP_LIMB - 4 - cnt_h); } else { topval[0] = ((mp_limb_t) 10) << (BITS_PER_MP_LIMB - 4); topval[1] = 0; (void) __mpn_lshift (topval, topval, 2, BITS_PER_MP_LIMB - cnt_h); } } /* We have to be careful when multiplying the last factor. If the result is greater than 1.0 be have to test it against 10.0. If it is greater or equal to 10.0 the multiplication was not valid. This is because we cannot determine the number of bits in the result in advance. */ if (incr < exponent + 3 || (incr == exponent + 3 && (tmp[tmpsize - 1] < topval[1] || (tmp[tmpsize - 1] == topval[1] && tmp[tmpsize - 2] < topval[0])))) { /* The factor is right. Adapt binary and decimal exponents. */ exponent -= incr; exp10 |= 1 << explog; /* If this factor yields a number greater or equal to 1.0, we must not shift the non-fractional digits down. */ if (exponent < 0) cnt_h += -exponent; /* Now we optimize the number representation. */ for (i = 0; tmp[i] == 0; ++i); if (cnt_h == BITS_PER_MP_LIMB - 1) { MPN_COPY (frac, tmp + i, tmpsize - i); fracsize = tmpsize - i; } else { count_trailing_zeros (cnt_l, tmp[i]); /* Now shift the numbers to their optimal position. */ if (i == 0 && BITS_PER_MP_LIMB - 1 - cnt_h > cnt_l) { /* We cannot save any memory. Just roll the number so that the leading digit is in a separate limb. */ cy = __mpn_lshift (frac, tmp, tmpsize, cnt_h + 1); fracsize = tmpsize + 1; frac[fracsize - 1] = cy; } else if (BITS_PER_MP_LIMB - 1 - cnt_h <= cnt_l) { (void) __mpn_rshift (frac, tmp + i, tmpsize - i, BITS_PER_MP_LIMB - 1 - cnt_h); fracsize = tmpsize - i; } else { /* We can only save the memory of the limbs which are zero. The non-zero parts occupy the same number of limbs. */ (void) __mpn_rshift (frac, tmp + (i - 1), tmpsize - (i - 1), BITS_PER_MP_LIMB - 1 - cnt_h); fracsize = tmpsize - (i - 1); } } used_limbs = fracsize - 1; } } --explog; } while (powers != &_fpioconst_pow10[1] && exponent > 0); /* All factors but 10^-1 are tested now. */ if (exponent > 0) { int cnt_l; cy = __mpn_mul_1 (tmp, frac, fracsize, 10); tmpsize = fracsize; assert (cy == 0 || tmp[tmpsize - 1] < 20); count_trailing_zeros (cnt_l, tmp[0]); if (cnt_l < MIN (4, exponent)) { cy = __mpn_lshift (frac, tmp, tmpsize, BITS_PER_MP_LIMB - MIN (4, exponent)); if (cy != 0) frac[tmpsize++] = cy; } else (void) __mpn_rshift (frac, tmp, tmpsize, MIN (4, exponent)); fracsize = tmpsize; exp10 |= 1; assert (frac[fracsize - 1] < 10); } exponent = exp10; } else { /* This is a special case. We don't need a factor because the numbers are in the range of 0.0 <= fp < 8.0. We simply shift it to the right place and divide it by 1.0 to get the leading digit. (Of course this division is not really made.) */ assert (0 <= exponent && exponent < 3 && exponent + to_shift < BITS_PER_MP_LIMB); /* Now shift the input value to its right place. */ cy = __mpn_lshift (frac, fp_input, fracsize, (exponent + to_shift)); frac[fracsize++] = cy; exponent = 0; } { int width = info->width; wchar_t *wbuffer, *wstartp, *wcp; int buffer_malloced; int chars_needed; int expscale; int intdig_max, intdig_no = 0; int fracdig_min, fracdig_max, fracdig_no = 0; int dig_max; int significant; int ngroups = 0; if (_tolower (info->spec) == 'e') { type = info->spec; intdig_max = 1; fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec; chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4; /* d . ddd e +- ddd */ dig_max = INT_MAX; /* Unlimited. */ significant = 1; /* Does not matter here. */ } else if (_tolower (info->spec) == 'f') { type = 'f'; fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec; dig_max = INT_MAX; /* Unlimited. */ significant = 1; /* Does not matter here. */ if (expsign == 0) { intdig_max = exponent + 1; /* This can be really big! */ /* XXX Maybe malloc if too big? */ chars_needed = exponent + 1 + 1 + fracdig_max; } else { intdig_max = 1; chars_needed = 1 + 1 + fracdig_max; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -