diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-12-27 15:36:51 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-12-27 15:36:51 +0000 |
commit | 05fa8834c6644f12405ea713c48693bf2d1864f1 (patch) | |
tree | c6b6391884370c75972a2e432d42ebbb076a0cdf /stdio-common/printf_fp.c | |
parent | 525c181a5a9a95e24d2111b7792608151a40eb84 (diff) | |
parent | 963c37d5c0eb62b38f8764b23931c0dcdd497a13 (diff) |
Merge commit 'refs/top-bases/t/bigmem' into t/bigmemt/bigmem
Diffstat (limited to 'stdio-common/printf_fp.c')
-rw-r--r-- | stdio-common/printf_fp.c | 260 |
1 files changed, 141 insertions, 119 deletions
diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c index 4134f8ab89..66ab59bad2 100644 --- a/stdio-common/printf_fp.c +++ b/stdio-common/printf_fp.c @@ -1,5 +1,5 @@ /* Floating point output for `printf'. - Copyright (C) 1995-2016 Free Software Foundation, Inc. + Copyright (C) 1995-2018 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. @@ -21,6 +21,7 @@ /* The gmp headers need some configuration frobs. */ #define HAVE_ALLOCA 1 +#include <array_length.h> #include <libioP.h> #include <alloca.h> #include <ctype.h> @@ -55,17 +56,12 @@ #endif #include <assert.h> -/* This defines make it possible to use the same code for GNU C library and - the GNU I/O library. */ #define PUT(f, s, n) _IO_sputn (f, s, n) #define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n)) -/* We use this file GNU C library and GNU I/O library. So make - names equal. */ #undef putc #define putc(c, f) (wide \ ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f)) -#define size_t _IO_size_t -#define FILE _IO_FILE + /* Macros for doing the actual output. */ @@ -139,14 +135,11 @@ extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size, extern mp_size_t __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size, int *expt, int *is_neg, long double value); -extern unsigned int __guess_grouping (unsigned int intdig_max, - const char *grouping); static wchar_t *group_number (wchar_t *buf, wchar_t *bufend, unsigned int intdig_no, const char *grouping, - wchar_t thousands_sep, int ngroups) - internal_function; + wchar_t thousands_sep, int ngroups); struct hack_digit_param { @@ -209,15 +202,18 @@ hack_digit (struct hack_digit_param *p) } int -___printf_fp (FILE *fp, - const struct printf_info *info, - const void *const *args) +__printf_fp_l (FILE *fp, locale_t loc, + const struct printf_info *info, + const void *const *args) { /* The floating-point value to output. */ union { double dbl; - __long_double_t ldbl; + long double ldbl; +#if __HAVE_DISTINCT_FLOAT128 + _Float128 f128; +#endif } fpnum; @@ -234,9 +230,17 @@ ___printf_fp (FILE *fp, const char *special = NULL; const wchar_t *wspecial = NULL; + /* When _Float128 is enabled in the library and ABI-distinct from long + double, we need mp_limbs enough for any of them. */ +#if __HAVE_DISTINCT_FLOAT128 +# define GREATER_MANT_DIG FLT128_MANT_DIG +#else +# define GREATER_MANT_DIG LDBL_MANT_DIG +#endif /* We need just a few limbs for the input before shifting to the right position. */ - mp_limb_t fp_input[(LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB]; + mp_limb_t fp_input[(GREATER_MANT_DIG + BITS_PER_MP_LIMB - 1) + / BITS_PER_MP_LIMB]; /* We need to shift the contents of fp_input by this amount of bits. */ int to_shift = 0; @@ -263,18 +267,19 @@ ___printf_fp (FILE *fp, /* Figure out the decimal point character. */ if (info->extra == 0) { - decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); - decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC); + decimal = _nl_lookup (loc, LC_NUMERIC, DECIMAL_POINT); + decimalwc = _nl_lookup_word + (loc, LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC); } else { - decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT); + decimal = _nl_lookup (loc, LC_MONETARY, MON_DECIMAL_POINT); if (*decimal == '\0') - decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); - decimalwc = _NL_CURRENT_WORD (LC_MONETARY, + decimal = _nl_lookup (loc, LC_NUMERIC, DECIMAL_POINT); + decimalwc = _nl_lookup_word (loc, LC_MONETARY, _NL_MONETARY_DECIMAL_POINT_WC); if (decimalwc == L'\0') - decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, + decimalwc = _nl_lookup_word (loc, LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC); } /* The decimal point character must not be zero. */ @@ -284,9 +289,9 @@ ___printf_fp (FILE *fp, if (info->group) { if (info->extra == 0) - grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); + grouping = _nl_lookup (loc, LC_NUMERIC, GROUPING); else - grouping = _NL_CURRENT (LC_MONETARY, MON_GROUPING); + grouping = _nl_lookup (loc, LC_MONETARY, MON_GROUPING); if (*grouping <= 0 || *grouping == CHAR_MAX) grouping = NULL; @@ -296,19 +301,20 @@ ___printf_fp (FILE *fp, if (wide) { if (info->extra == 0) - thousands_sepwc = - _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC); + thousands_sepwc = _nl_lookup_word + (loc, LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC); else thousands_sepwc = - _NL_CURRENT_WORD (LC_MONETARY, + _nl_lookup_word (loc, LC_MONETARY, _NL_MONETARY_THOUSANDS_SEP_WC); } else { if (info->extra == 0) - thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); + thousands_sep = _nl_lookup (loc, LC_NUMERIC, THOUSANDS_SEP); else - thousands_sep = _NL_CURRENT (LC_MONETARY, MON_THOUSANDS_SEP); + thousands_sep = _nl_lookup + (loc, LC_MONETARY, MON_THOUSANDS_SEP); } if ((wide && thousands_sepwc == L'\0') @@ -325,94 +331,62 @@ ___printf_fp (FILE *fp, else grouping = NULL; +#define PRINTF_FP_FETCH(FLOAT, VAR, SUFFIX, MANT_DIG) \ + { \ + (VAR) = *(const FLOAT *) args[0]; \ + \ + /* Check for special values: not a number or infinity. */ \ + if (isnan (VAR)) \ + { \ + is_neg = signbit (VAR); \ + if (isupper (info->spec)) \ + { \ + special = "NAN"; \ + wspecial = L"NAN"; \ + } \ + else \ + { \ + special = "nan"; \ + wspecial = L"nan"; \ + } \ + } \ + else if (isinf (VAR)) \ + { \ + is_neg = signbit (VAR); \ + if (isupper (info->spec)) \ + { \ + special = "INF"; \ + wspecial = L"INF"; \ + } \ + else \ + { \ + special = "inf"; \ + wspecial = L"inf"; \ + } \ + } \ + else \ + { \ + p.fracsize = __mpn_extract_##SUFFIX \ + (fp_input, array_length (fp_input), \ + &p.exponent, &is_neg, VAR); \ + to_shift = 1 + p.fracsize * BITS_PER_MP_LIMB - MANT_DIG; \ + } \ + } + /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + PRINTF_FP_FETCH (_Float128, fpnum.f128, float128, FLT128_MANT_DIG) + else +#endif #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) - { - fpnum.ldbl = *(const long double *) args[0]; - - /* Check for special values: not a number or infinity. */ - if (isnan (fpnum.ldbl)) - { - is_neg = signbit (fpnum.ldbl); - if (isupper (info->spec)) - { - special = "NAN"; - wspecial = L"NAN"; - } - else - { - special = "nan"; - wspecial = L"nan"; - } - } - else if (isinf (fpnum.ldbl)) - { - is_neg = signbit (fpnum.ldbl); - if (isupper (info->spec)) - { - special = "INF"; - wspecial = L"INF"; - } - else - { - special = "inf"; - wspecial = L"inf"; - } - } - else - { - p.fracsize = __mpn_extract_long_double (fp_input, - (sizeof (fp_input) / - sizeof (fp_input[0])), - &p.exponent, &is_neg, - fpnum.ldbl); - to_shift = 1 + p.fracsize * BITS_PER_MP_LIMB - LDBL_MANT_DIG; - } - } + PRINTF_FP_FETCH (long double, fpnum.ldbl, long_double, LDBL_MANT_DIG) else -#endif /* no long double */ - { - fpnum.dbl = *(const double *) args[0]; +#endif + PRINTF_FP_FETCH (double, fpnum.dbl, double, DBL_MANT_DIG) - /* Check for special values: not a number or infinity. */ - if (isnan (fpnum.dbl)) - { - is_neg = signbit (fpnum.dbl); - if (isupper (info->spec)) - { - special = "NAN"; - wspecial = L"NAN"; - } - else - { - special = "nan"; - wspecial = L"nan"; - } - } - else if (isinf (fpnum.dbl)) - { - is_neg = signbit (fpnum.dbl); - if (isupper (info->spec)) - { - special = "INF"; - wspecial = L"INF"; - } - else - { - special = "inf"; - wspecial = L"inf"; - } - } - else - { - p.fracsize = __mpn_extract_double (fp_input, - (sizeof (fp_input) - / sizeof (fp_input[0])), - &p.exponent, &is_neg, fpnum.dbl); - to_shift = 1 + p.fracsize * BITS_PER_MP_LIMB - DBL_MANT_DIG; - } - } +#undef PRINTF_FP_FETCH if (special) { @@ -448,7 +422,8 @@ ___printf_fp (FILE *fp, { mp_size_t bignum_size = ((abs (p.exponent) + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB - + (LDBL_MANT_DIG / BITS_PER_MP_LIMB > 2 ? 8 : 4)) + + (GREATER_MANT_DIG / BITS_PER_MP_LIMB > 2 + ? 8 : 4)) * sizeof (mp_limb_t); p.frac = (mp_limb_t *) alloca (bignum_size); p.tmp = (mp_limb_t *) alloca (bignum_size); @@ -463,7 +438,15 @@ ___printf_fp (FILE *fp, { /* |FP| >= 8.0. */ int scaleexpo = 0; - int explog = LDBL_MAX_10_EXP_LOG; + int explog; +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + explog = FLT128_MAX_10_EXP_LOG; + else + explog = LDBL_MAX_10_EXP_LOG; +#else + explog = LDBL_MAX_10_EXP_LOG; +#endif int exp10 = 0; const struct mp_power *powers = &_fpioconst_pow10[explog + 1]; int cnt_h, cnt_l, i; @@ -497,6 +480,27 @@ ___printf_fp (FILE *fp, { if (p.scalesize == 0) { +#if __HAVE_DISTINCT_FLOAT128 + if ((FLT128_MANT_DIG + > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB) + && info->is_binary128) + { +#define _FLT128_FPIO_CONST_SHIFT \ + (((FLT128_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) \ + - _FPIO_CONST_OFFSET) + /* 64bit const offset is not enough for + IEEE 854 quad long double (_Float128). */ + p.tmpsize = powers->arraysize + _FLT128_FPIO_CONST_SHIFT; + memcpy (p.tmp + _FLT128_FPIO_CONST_SHIFT, + &__tens[powers->arrayoff], + p.tmpsize * sizeof (mp_limb_t)); + MPN_ZERO (p.tmp, _FLT128_FPIO_CONST_SHIFT); + /* Adjust p.exponent, as scaleexpo will be this much + bigger too. */ + p.exponent += _FLT128_FPIO_CONST_SHIFT * BITS_PER_MP_LIMB; + } + else +#endif /* __HAVE_DISTINCT_FLOAT128 */ #ifndef __NO_LONG_DOUBLE_MATH if (LDBL_MANT_DIG > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB && info->is_long_double) @@ -637,7 +641,15 @@ ___printf_fp (FILE *fp, { /* |FP| < 1.0. */ int exp10 = 0; - int explog = LDBL_MAX_10_EXP_LOG; + int explog; +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + explog = FLT128_MAX_10_EXP_LOG; + else + explog = LDBL_MAX_10_EXP_LOG; +#else + explog = LDBL_MAX_10_EXP_LOG; +#endif const struct mp_power *powers = &_fpioconst_pow10[explog + 1]; /* Now shift the input value to its right place. */ @@ -1171,9 +1183,11 @@ ___printf_fp (FILE *fp, size_t decimal_len; size_t thousands_sep_len; wchar_t *copywc; - size_t factor = (info->i18n - ? _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX) - : 1); + size_t factor; + if (info->i18n) + factor = _nl_lookup_word (loc, LC_CTYPE, _NL_CTYPE_MB_CUR_MAX); + else + factor = 1; decimal_len = strlen (decimal); @@ -1244,8 +1258,17 @@ ___printf_fp (FILE *fp, } return done; } +libc_hidden_def (__printf_fp_l) + +int +___printf_fp (FILE *fp, const struct printf_info *info, + const void *const *args) +{ + return __printf_fp_l (fp, _NL_CURRENT_LOCALE, info, args); +} ldbl_hidden_def (___printf_fp, __printf_fp) ldbl_strong_alias (___printf_fp, __printf_fp) + /* Return the number of extra grouping characters that will be inserted into a number with INTDIG_MAX integer digits. */ @@ -1290,7 +1313,6 @@ __guess_grouping (unsigned int intdig_max, const char *grouping) Return the new end of buffer. */ static wchar_t * -internal_function group_number (wchar_t *buf, wchar_t *bufend, unsigned int intdig_no, const char *grouping, wchar_t thousands_sep, int ngroups) { |