📄 printf_fp.c
字号:
} else { dig_max = info->prec < 0 ? 6 : (info->prec == 0 ? 1 : info->prec); if ((expsign == 0 && exponent >= dig_max) || (expsign != 0 && exponent > 4)) { if ('g' - 'G' == 'e' - 'E') type = 'E' + (info->spec - 'G'); else type = isupper (info->spec) ? 'E' : 'e'; fracdig_max = dig_max - 1; intdig_max = 1; chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4; } else { type = 'f'; intdig_max = expsign == 0 ? exponent + 1 : 0; fracdig_max = dig_max - intdig_max; /* We need space for the significant digits and perhaps for leading zeros when < 1.0. The number of leading zeros can be as many as would be required for exponential notation with a negative two-digit exponent, which is 4. */ chars_needed = dig_max + 1 + 4; } fracdig_min = info->alt ? fracdig_max : 0; significant = 0; /* We count significant digits. */ } if (grouping) { /* Guess the number of groups we will make, and thus how many spaces we need for separator characters. */ ngroups = __guess_grouping (intdig_max, grouping); chars_needed += ngroups; } /* Allocate buffer for output. We need two more because while rounding it is possible that we need two more characters in front of all the other output. If the amount of memory we have to allocate is too large use `malloc' instead of `alloca'. */ buffer_malloced = ! __libc_use_alloca (chars_needed * 2 * sizeof (wchar_t)); if (buffer_malloced) { wbuffer = (wchar_t *) malloc ((2 + chars_needed) * sizeof (wchar_t)); if (wbuffer == NULL) /* Signal an error to the caller. */ return -1; } else wbuffer = (wchar_t *) alloca ((2 + chars_needed) * sizeof (wchar_t)); wcp = wstartp = wbuffer + 2; /* Let room for rounding. */ /* Do the real work: put digits in allocated buffer. */ if (expsign == 0 || type != 'f') { assert (expsign == 0 || intdig_max == 1); while (intdig_no < intdig_max) { ++intdig_no; *wcp++ = hack_digit (); } significant = 1; if (info->alt || fracdig_min > 0 || (fracdig_max > 0 && (fracsize > 1 || frac[0] != 0))) *wcp++ = decimalwc; } else { /* |fp| < 1.0 and the selected type is 'f', so put "0." in the buffer. */ *wcp++ = L'0'; --exponent; *wcp++ = decimalwc; } /* Generate the needed number of fractional digits. */ while (fracdig_no < fracdig_min || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0))) { ++fracdig_no; *wcp = hack_digit (); if (*wcp++ != L'0') significant = 1; else if (significant == 0) { ++fracdig_max; if (fracdig_min > 0) ++fracdig_min; } } /* Do rounding. */ digit = hack_digit (); if (digit > L'4') { wchar_t *wtp = wcp; if (digit == L'5' && ((*(wcp - 1) != decimalwc && (*(wcp - 1) & 1) == 0) || ((*(wcp - 1) == decimalwc && (*(wcp - 2) & 1) == 0)))) { /* This is the critical case. */ if (fracsize == 1 && frac[0] == 0) /* Rest of the number is zero -> round to even. (IEEE 754-1985 4.1 says this is the default rounding.) */ goto do_expo; else if (scalesize == 0) { /* Here we have to see whether all limbs are zero since no normalization happened. */ size_t lcnt = fracsize; while (lcnt >= 1 && frac[lcnt - 1] == 0) --lcnt; if (lcnt == 0) /* Rest of the number is zero -> round to even. (IEEE 754-1985 4.1 says this is the default rounding.) */ goto do_expo; } } if (fracdig_no > 0) { /* Process fractional digits. Terminate if not rounded or radix character is reached. */ while (*--wtp != decimalwc && *wtp == L'9') *wtp = '0'; if (*wtp != decimalwc) /* Round up. */ (*wtp)++; } if (fracdig_no == 0 || *wtp == decimalwc) { /* Round the integer digits. */ if (*(wtp - 1) == decimalwc) --wtp; while (--wtp >= wstartp && *wtp == L'9') *wtp = L'0'; if (wtp >= wstartp) /* Round up. */ (*wtp)++; else /* It is more critical. All digits were 9's. */ { if (type != 'f') { *wstartp = '1'; exponent += expsign == 0 ? 1 : -1; } else if (intdig_no == dig_max) { /* This is the case where for type %g the number fits really in the range for %f output but after rounding the number of digits is too big. */ *--wstartp = decimalwc; *--wstartp = L'1'; if (info->alt || fracdig_no > 0) { /* Overwrite the old radix character. */ wstartp[intdig_no + 2] = L'0'; ++fracdig_no; } fracdig_no += intdig_no; intdig_no = 1; fracdig_max = intdig_max - intdig_no; ++exponent; /* Now we must print the exponent. */ type = isupper (info->spec) ? 'E' : 'e'; } else { /* We can simply add another another digit before the radix. */ *--wstartp = L'1'; ++intdig_no; } /* While rounding the number of digits can change. If the number now exceeds the limits remove some fractional digits. */ if (intdig_no + fracdig_no > dig_max) { wcp -= intdig_no + fracdig_no - dig_max; fracdig_no -= intdig_no + fracdig_no - dig_max; } } } } do_expo: /* Now remove unnecessary '0' at the end of the string. */ while (fracdig_no > fracdig_min && *(wcp - 1) == L'0') { --wcp; --fracdig_no; } /* If we eliminate all fractional digits we perhaps also can remove the radix character. */ if (fracdig_no == 0 && !info->alt && *(wcp - 1) == decimalwc) --wcp; if (grouping) /* Add in separator characters, overwriting the same buffer. */ wcp = group_number (wstartp, wcp, intdig_no, grouping, thousands_sepwc, ngroups); /* Write the exponent if it is needed. */ if (type != 'f') { *wcp++ = (wchar_t) type; *wcp++ = expsign ? L'-' : L'+'; /* Find the magnitude of the exponent. */ expscale = 10; while (expscale <= exponent) expscale *= 10; if (exponent < 10) /* Exponent always has at least two digits. */ *wcp++ = L'0'; else do { expscale /= 10; *wcp++ = L'0' + (exponent / expscale); exponent %= expscale; } while (expscale > 10); *wcp++ = L'0' + exponent; } /* Compute number of characters which must be filled with the padding character. */ if (is_neg || info->showsign || info->space) --width; width -= wcp - wstartp; if (!info->left && info->pad != '0' && width > 0) PADN (info->pad, width); if (is_neg) outchar ('-'); else if (info->showsign) outchar ('+'); else if (info->space) outchar (' '); if (!info->left && info->pad == '0' && width > 0) PADN ('0', width); { char *buffer = NULL; char *cp = NULL; char *tmpptr; if (! wide) { /* Create the single byte string. */ size_t decimal_len; size_t thousands_sep_len; wchar_t *copywc; decimal_len = strlen (decimal); if (thousands_sep == NULL) thousands_sep_len = 0; else thousands_sep_len = strlen (thousands_sep); if (buffer_malloced) { buffer = (char *) malloc (2 + chars_needed + decimal_len + ngroups * thousands_sep_len); if (buffer == NULL) /* Signal an error to the caller. */ return -1; } else buffer = (char *) alloca (2 + chars_needed + decimal_len + ngroups * thousands_sep_len); /* Now copy the wide character string. Since the character (except for the decimal point and thousands separator) must be coming from the ASCII range we can esily convert the string without mapping tables. */ for (cp = buffer, copywc = wstartp; copywc < wcp; ++copywc) if (*copywc == decimalwc) cp = (char *) __mempcpy (cp, decimal, decimal_len); else if (*copywc == thousands_sepwc) cp = (char *) __mempcpy (cp, thousands_sep, thousands_sep_len); else *cp++ = (char) *copywc; } tmpptr = buffer; if (__builtin_expect (info->i18n, 0)) {#ifdef COMPILE_WPRINTF wstartp = _i18n_number_rewrite (wstartp, wcp);#else tmpptr = _i18n_number_rewrite (tmpptr, cp);#endif } PRINT (tmpptr, wstartp, wide ? wcp - wstartp : cp - tmpptr); /* Free the memory if necessary. */ if (buffer_malloced) { free (buffer); free (wbuffer); } } if (info->left && width > 0) PADN (info->pad, width); } return done;}libc_hidden_def (__printf_fp)/* Return the number of extra grouping characters that will be inserted into a number with INTDIG_MAX integer digits. */unsigned int__guess_grouping (unsigned int intdig_max, const char *grouping){ unsigned int groups; /* We treat all negative values like CHAR_MAX. */ if (*grouping == CHAR_MAX || *grouping <= 0) /* No grouping should be done. */ return 0; groups = 0; while (intdig_max > (unsigned int) *grouping) { ++groups; intdig_max -= *grouping++; if (*grouping == CHAR_MAX#if CHAR_MIN < 0 || *grouping < 0#endif ) /* No more grouping should be done. */ break; else if (*grouping == 0) { /* Same grouping repeats. */ groups += (intdig_max - 1) / grouping[-1]; break; } } return groups;}/* Group the INTDIG_NO integer digits of the number in [BUF,BUFEND). There is guaranteed enough space past BUFEND to extend it. Return the new end of buffer. */static wchar_t *internal_functiongroup_number (wchar_t *buf, wchar_t *bufend, unsigned int intdig_no, const char *grouping, wchar_t thousands_sep, int ngroups){ wchar_t *p; if (ngroups == 0) return bufend; /* Move the fractional part down. */ __wmemmove (buf + intdig_no + ngroups, buf + intdig_no, bufend - (buf + intdig_no)); p = buf + intdig_no + ngroups - 1; do { unsigned int len = *grouping++; do *p-- = buf[--intdig_no]; while (--len > 0); *p-- = thousands_sep; if (*grouping == CHAR_MAX#if CHAR_MIN < 0 || *grouping < 0#endif ) /* No more grouping should be done. */ break; else if (*grouping == 0) /* Same grouping repeats. */ --grouping; } while (intdig_no > (unsigned int) *grouping); /* Copy the remaining ungrouped digits. */ do *p-- = buf[--intdig_no]; while (p > buf); return bufend + ngroups;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -