summaryrefslogtreecommitdiff
path: root/vasprintf.c
diff options
context:
space:
mode:
authorthevenyp <thevenyp@280ebfd0-de03-0410-8827-d642c229c3f4>2008-01-17 17:46:53 +0000
committerthevenyp <thevenyp@280ebfd0-de03-0410-8827-d642c229c3f4>2008-01-17 17:46:53 +0000
commitf90c9b1062d0837c0a6825364884e872d085d472 (patch)
treed191811f1f38423c863b80df927112393c81c6b3 /vasprintf.c
parent3b4f918ad52d74ecd6d42e0f66dd40841f978147 (diff)
downloadmpfr-f90c9b1062d0837c0a6825364884e872d085d472.tar.gz
vasprintf.c: merge code for "%Ra" and "%Rb"
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@5199 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'vasprintf.c')
-rw-r--r--vasprintf.c1117
1 files changed, 347 insertions, 770 deletions
diff --git a/vasprintf.c b/vasprintf.c
index e9f6a7cd3..1cc8c1b34 100644
--- a/vasprintf.c
+++ b/vasprintf.c
@@ -599,720 +599,6 @@ sprnt_int (struct string_buffer *buf, mpfr_srcptr p, struct printf_spec spec)
return length;
}
-/* sprnt_fp_a prints a mpfr_t in "%a" and "%A" cases.
- return the size of the string (not counting the terminating '\0')
- return -1 if the built string is too long (i.e. has more than
- MAX_CHAR_BY_SPEC characters). */
-static int
-sprnt_fp_a (struct string_buffer *buf, mpfr_srcptr p, struct printf_spec spec)
-{
- char *str;
- const char d_point[] = { MPFR_DECIMAL_POINT, '\0' };
-
- /* char_fp details how much characters are needed in each part of a float
- print.
- total must be less or equal to MAX_CHAR_BY_SPEC. */
- struct char_fp
- {
- int sgn; /* 1 if sign char is present */
- int point; /* 1 if decimal point char */
- int int_part; /* Size of integral part */
- int frac_part; /* Size of fractional part */
- int exp_part; /* Size of exponent (always in base ten) */
-
- int total; /* Total size: sum of the precedent fields
- plus the base prefix */
- };
-
- struct char_fp nbc;
-
- if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (p)))
- {
- if (MPFR_IS_NAN (p))
- {
- if (spec.spec == 'A')
- {
- nbc.total = MPFR_NAN_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + nbc.total);
- strcpy (str, MPFR_NAN_STRING_UC);
- }
- else
- {
- nbc.total = MPFR_NAN_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + nbc.total);
- strcpy (str, MPFR_NAN_STRING_LC);
- }
- }
- else if (MPFR_IS_INF (p))
- {
- if (spec.spec == 'A')
- {
- nbc.total = MPFR_INF_STRING_LENGTH;
- nbc.total += (MPFR_SIGN (p) < 0) ? 1 : 0;
- str = (char *) (*__gmp_allocate_func) (1 + nbc.total);
- str[0] = '\0';
- if (MPFR_SIGN (p) < 0)
- strcat (str, "-");
- strcat (str, MPFR_INF_STRING_UC);
- }
- else
- {
- nbc.total = MPFR_INF_STRING_LENGTH;
- nbc.total += (MPFR_SIGN (p) < 0) ? 1 : 0;
- str = (char *) (*__gmp_allocate_func) (1 + nbc.total);
- str[0] = '\0';
- if (MPFR_SIGN (p) < 0)
- strcat (str, "-");
- strcat (str, MPFR_INF_STRING_LC);
- }
- }
- else
- /* p == 0 */
- {
- /* First, we compute how much characters will be displayed */
- nbc.sgn =
- (MPFR_SIGN (p) < 0) || spec.showsign || spec.space ? 1 : 0;
- nbc.frac_part = (spec.prec < 0) ? 0 : spec.prec;
- nbc.point = (nbc.frac_part == 0) && (spec.alt == 0) ? 0 : 1;
- nbc.exp_part = 3; /* 3 characters: "p+0" or "P+0" */
- nbc.total = nbc.sgn + nbc.point + nbc.frac_part + nbc.exp_part;
- nbc.total += 2; /* 2 characters "0x" or "0X" */
- if ((spec.left == 0) && (spec.pad == '0')
- && (nbc.total < spec.width))
- /* pad with leading zeros */
- nbc.int_part = spec.width - nbc.total;
- else
- /* we only need the character '0' */
- nbc.int_part = 1;
- nbc.total += nbc.int_part;
-
- if ((nbc.total < 0) || (nbc.total > MAX_CHAR_BY_SPEC))
- /* spec.prec is too close to MAX_CHAR_BY_SPEC */
- return -1;
-
- str = (char *)(*__gmp_allocate_func) (nbc.total + 1);
-
- /* Now, we build the string */
- if (nbc.sgn != 0)
- /* signed zero */
- {
- str[0] =
- (MPFR_SIGN (p) < 0) ? '-' : (spec.showsign) ? '+' : ' ';
- str[1] = '\0';
- }
- else
- /* positive zero, no sign displayed */
- str[0] = '\0';
- /* prefix */
- strcat (str, (spec.spec == 'A') ? "0X" : "0x");
- /* integral part, with optional padding */
- {
- int i;
- for (i = 1; i < nbc.int_part; ++i)
- strcat (str, "0");
- }
- /* digit */
- strcat (str, "0");
- if (nbc.point == 1)
- strcat (str, d_point);
- if (nbc.frac_part > 0)
- {
- /* fill frac_part with '0' */
- int i;
- for (i = 0; i < nbc.frac_part; i++)
- strcat (str, "0");
- }
- /* exponent */
- strcat (str, (spec.spec == 'A') ? "P+0" : "p+0");
- MPFR_ASSERTD (nbc.total == strlen (str));
- }
- }
- else
- /* p is a regular number, p != 0*/
- {
- mp_exp_t exp;
- char *raw_str;
- char *raw_str_cur; /* cursor in raw_str */
-
- /* get sign - and significant digits in raw_str */
- if (spec.prec < 0)
- /* Let mpfr_get_str determine precision. */
- {
- raw_str = mpfr_get_str (0, &exp, 16, 0, p, spec.rnd_mode);
- /* exp is the exponent for radix sixteen with decimal point BEFORE
- the first digit, we want the exponent for radix two and the
- decimal point AFTER the first digit */
- exp = (exp - 1) * 4;
-
- }
- else if (spec.prec > 0)
- /* One digit before decimal point plus SPEC.PREC after it. */
- {
- raw_str = mpfr_get_str (0, &exp, 16, 1 + spec.prec, p,
- spec.rnd_mode);
- /* exp is the exponent for radix sixteen with decimal point BEFORE
- the first digit, we want the exponent for radix two and the
- decimal point AFTER the first digit */
- exp = (exp - 1) * 4;
- }
- else
- /* One digit is sufficient but mpfr_get_str returns at least two
- digits. So, in order to avoid double rounding, we will build
- ourselves the raw string. */
- {
- mp_limb_t *pm = MPFR_MANT (p);
- mp_size_t ps;
- size_t n;
- int digit, shift;
- char digit_str[2] = {'\0', '\0'};
- int rnd_away;
-
- /* rnd_away:
- 1 if round away from zero,
- 0 if round to zero,
- -1 if not decided yet. */
- rnd_away =
- spec.rnd_mode == GMP_RNDD ? MPFR_IS_NEG (p) :
- spec.rnd_mode == GMP_RNDU ? MPFR_IS_POS (p) :
- spec.rnd_mode == GMP_RNDZ ? 0 : -1;
-
- /* Find out the radix-16 digit by grouping the 4 first digits. Even
- if MPFR_PREC (p) < 4, we can read 4 bits in its first limb */
- exp = MPFR_GET_EXP (p);
- shift = BITS_PER_MP_LIMB - 4;
- ps = (MPFR_PREC (p) - 1) / BITS_PER_MP_LIMB;
- digit = pm[ps]>>shift;
-
- /* exponent for radix-2 with the decimal point after the first
- hexadecimal digit */
- exp -= 4;
-
- if (MPFR_PREC (p) > 4)
- /* round taking into account bits outside the first 4 ones */
- {
- if (rnd_away == -1)
- /* Round to nearest mode: we have to decide in that particular
- case if we have to round to away from zero or not */
- {
- mp_limb_t limb, rb, mask;
- /* compute rounding bit */
- mask = MPFR_LIMB_ONE << (shift - 1);
- rb = pm[ps] & mask;
- if (rb == 0)
- rnd_away = 0;
- else
- {
- mask = MPFR_LIMB_MASK (shift);
- limb = pm[ps] & mask;
- while ((ps > 0) && (limb == 0))
- limb = pm[--ps];
- if (limb == 0)
- /* tie case, round to even */
- rnd_away = (digit & 1) ? 1 : 0;
- else
- rnd_away = 1;
- }
- }
-
- if (rnd_away == 1)
- {
- digit++;
- if (digit > 15)
- /* As we want only the first significant digit, we have
- to shift one position to the left */
- {
- digit >>= 1;
- exp += 1; /* no possible overflow because
- exp < MPFR_EXP_MAX/4 */
- }
- }
- }
-
- n = 2 * sizeof (char);
- n += (MPFR_SIGN (p) < 0) ? 1 : 0;
- raw_str = (char *)(*__gmp_allocate_func) (n);
- raw_str[0] = '\0';
-
- if (MPFR_SIGN (p) < 0)
- strcat (raw_str, "-");
-
- MPFR_ASSERTD ((0 <= digit) && (digit <= 15));
- digit_str[0] = num_to_text [digit];
-
- strcat (raw_str, digit_str);
- }
-
- raw_str_cur = raw_str;
- if (spec.spec == 'A')
- /* All digits in upper case */
- {
- char *s1 = raw_str;
- while (*s1)
- {
- switch (*s1)
- {
- case 'a':
- *s1 = 'A';
- break;
- case 'b':
- *s1 = 'B';
- break;
- case 'c':
- *s1 = 'C';
- break;
- case 'd':
- *s1 = 'D';
- break;
- case 'e':
- *s1 = 'E';
- break;
- case 'f':
- *s1 = 'F';
- break;
- }
- s1++;
- }
- }
-
- /* compute the number of characters in each part of str */
- nbc.sgn = (MPFR_SIGN (p) < 0) || (spec.showsign) || (spec.space)
- ? 1 : 0;
- if (spec.prec < 0)
- {
- size_t ndigits;
- char *end;
-
- /* raw_str contains the sign if negative, the first digit that will
- be printed before the decimal point and all other digits are in
- the fractional part */
- ndigits = strlen (raw_str);
- ndigits -= (MPFR_SIGN (p) < 0) ? 2 : 1;
- /* we remove the trailing zeros if any */
- for (end = raw_str + strlen (raw_str) - 1;
- (*end == '0') && (ndigits > 0); --end)
- --ndigits;
-
- if (ndigits > INT_MAX)
- /* overflow error */
- {
- mpfr_free_str (raw_str);
- return -1;
- }
- else
- nbc.frac_part = (int) ndigits;
- }
- else
- nbc.frac_part = spec.prec;
- nbc.point = (nbc.frac_part == 0) && (spec.alt == 0) ? 0 : 1;
- /* The exp_part contains the base character plus the sign character
- plus (exp == 0) ? 1 : floor(log10(abs(exp))) + 1 digits.
- We assume that |exp| < 10^INT_MAX. */
- nbc.exp_part = 3;
- {
- mp_exp_unsigned_t x;
-
- x = SAFE_ABS (mp_exp_unsigned_t, exp);
- while (x > 9)
- {
- nbc.exp_part++;
- x /= 10;
- }
- }
- /* Number of characters to be printed (2 for "0x") */
- nbc.total = 2 + nbc.sgn + nbc.point + nbc.frac_part + nbc.exp_part;
- /* optional leading zeros are counted in int_part */
- if ((spec.left == 0) && (spec.pad == '0') && (nbc.total < spec.width))
- nbc.int_part = spec.width - nbc.total;
- else
- nbc.int_part = 1;
- nbc.total += nbc.int_part;
-
- if ((nbc.total < 0) || (nbc.total > MAX_CHAR_BY_SPEC))
- /* This happens when spec.width, spec.prec, or nbc.exp_part are too
- close to MAX_CHAR_BY_SPEC */
- {
- mpfr_free_str (raw_str);
- return -1;
- }
-
- str = (char *) (*__gmp_allocate_func) (nbc.total + 1);
- str[0] = '\0';
-
- /* Build str from raw_str */
- /* sign */
- if (nbc.sgn != 0)
- {
- if (MPFR_SIGN (p) < 0)
- {
- strcat (str, "-");
- ++raw_str_cur;
- }
- else if (spec.showsign)
- strcat (str, "+");
- else if (spec.space)
- strcat (str, " ");
- }
- /* base prefix */
- strcat (str, (spec.spec == 'A') ? "0X" : "0x");
- /* optional padding with leading zeros */
- {
- int i;
- for (i = nbc.int_part - 1; i > 0; i--)
- strcat (str, "0");
- }
- /* first digit */
- {
- char d[2];
- d[0] = *raw_str_cur++;
- d[1] = '\0';
- strcat (str, d);
- }
-
- if (nbc.frac_part == 0)
- /* no fractional part, optional decimal point */
- {
- if (spec.alt)
- strcat (str, d_point);
- }
- else
- /* a decimal point followed by fractional part */
- {
- char c;
-
- strcat (str, d_point);
- /* Don't take some trailing zeros into account */
- c = raw_str_cur[nbc.frac_part];
- raw_str_cur[nbc.frac_part] = '\0';
- strcat (str, raw_str_cur);
- /* we need to replace raw_str in its initial state in order to be
- correctly freed by mpfr_free_str */
- raw_str_cur[nbc.frac_part] = c;
- }
-
- /* exponent part */
- {
- char exp_fmt[8];
- char *exp_str;
-
- exp_fmt[0] = (spec.spec == 'A') ? 'P' : 'p';
- exp_fmt[1] = '\0';
- strcat (exp_fmt, "%+.1" MPFR_EXP_FORMAT_SPEC);
- exp_str = (char *) (*__gmp_allocate_func) (nbc.exp_part + 1);
-#if (__GMP_MP_SIZE_T_INT == 1)
- MPFR_ASSERTN (exp >= INT_MIN);
- MPFR_ASSERTN (exp <= INT_MAX);
-#elif (__GMP_MP_SIZE_T_INT == 0)
- MPFR_ASSERTN (exp >= LONG_MIN);
- MPFR_ASSERTN (exp <= LONG_MAX);
-#else
-#error "mp_exp_t size not supported"
-#endif
- if (sprintf (exp_str, exp_fmt, exp) < 0)
- {
- (*__gmp_free_func) (exp_str, nbc.exp_part + 1);
- mpfr_free_str (raw_str);
- (*__gmp_free_func) (str, nbc.total + 1);
-
- return -1;
- }
- strcat (str, exp_str);
- (*__gmp_free_func) (exp_str, nbc.exp_part + 1);
- }
-
- mpfr_free_str (raw_str);
- MPFR_ASSERTD (nbc.total == strlen (str));
- }
-
- /* right justification padding */
- if ((spec.left == 0) && (spec.width > nbc.total))
- buffer_pad (buf, ' ', spec.width - nbc.total);
-
- buffer_cat (buf, str, nbc.total);
-
- /* left justification padding */
- if ((spec.left == 1) && (spec.width > nbc.total))
- buffer_pad (buf, ' ', spec.width - nbc.total);
-
- mpfr_free_str (str);
- return nbc.total;
-}
-
-/* sprnt_fp_b prints a mpfr_t in "%b" case.
- If spec.prec == 0, we will output 1 digit after the decimal point except
- when p is zero (output "0p+0"). */
-static int
-sprnt_fp_b (struct string_buffer *buf, mpfr_srcptr p, struct printf_spec spec)
-{
- const char d_point[] = { MPFR_DECIMAL_POINT, '\0' };
- char *str;
-
- /* char_fp details how much characters are needed in each part of a float
- print.
- total must be less or equal to MAX_CHAR_BY_SPEC. */
- struct char_fp
- {
- int sgn; /* 1 if sign char is present */
- int point; /* 1 if decimal point char */
- int int_part; /* Size of integral part */
- int frac_part; /* Size of fractional part */
- int exp_part; /* Size of exponent (in base ten) */
-
- int total; /* Total size: sum of the precedent fields */
- };
-
- struct char_fp nbc;
-
- if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (p)))
- {
- if (MPFR_IS_NAN (p))
- {
- nbc.total = MPFR_NAN_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + nbc.total);
- strcpy (str, MPFR_NAN_STRING_LC);
- }
- else if (MPFR_IS_INF (p))
- {
- nbc.total = MPFR_INF_STRING_LENGTH;
- nbc.total += (MPFR_SIGN (p) < 0) ? 1 : 0;
- str = (char *) (*__gmp_allocate_func) (1 + nbc.total);
- str[0] = '\0';
- if (MPFR_SIGN (p) < 0)
- strcat (str, "-");
- strcat (str, MPFR_INF_STRING_LC);
- }
- else
- /* p == 0 */
- {
- /* First, we compute how much characters will be displayed */
- nbc.sgn =
- (MPFR_SIGN (p) < 0) || spec.showsign || spec.space ? 1 : 0;
- nbc.frac_part = (spec.prec < 0) ? 0 : spec.prec;
- nbc.point = (nbc.frac_part == 0) && (spec.alt == 0) ? 0 : 1;
- nbc.exp_part = 3; /* 3 characters: "p+0" */
- nbc.total = nbc.sgn + nbc.point + nbc.frac_part + nbc.exp_part;
- if ((spec.left == 0) && (spec.pad == '0')
- && (nbc.total < spec.width))
- /* pad with leading zeros */
- nbc.int_part = spec.width - nbc.total;
- else
- /* we only need the character '0' */
- nbc.int_part = 1;
- nbc.total += nbc.int_part;
-
- if ((nbc.total < 0) || (nbc.total > MAX_CHAR_BY_SPEC))
- /* spec.prec is too close to MAX_CHAR_BY_SPEC */
- return -1;
-
- str = (char *)(*__gmp_allocate_func) (nbc.total + 1);
-
- /* Now, we build the string */
- if (nbc.sgn != 0)
- /* signed zero */
- {
- str[0] =
- (MPFR_SIGN (p) < 0) ? '-' : (spec.showsign) ? '+' : ' ';
- str[1] = '\0';
- }
- else
- /* positive zero, no sign displayed */
- str[0] = '\0';
- /* integral part, with optional padding */
- {
- int i;
- for (i = 1; i < nbc.int_part; ++i)
- strcat (str, "0");
- }
- /* digit */
- strcat (str, "0");
- if (nbc.point == 1)
- strcat (str, d_point);
- if (nbc.frac_part > 0)
- {
- /* fill frac_part with '0' */
- int i;
- for (i = 0; i < nbc.frac_part; i++)
- strcat (str, "0");
- }
- /* exponent */
- strcat (str, "p+0");
- MPFR_ASSERTD (nbc.total == strlen (str));
- }
- }
- else
- /* p is a regular number, p != 0*/
- {
- mp_exp_t exp;
- char *raw_str;
- char *raw_str_cur; /* cursor in raw_str */
- int nsd;
-
- /* Number of significant digits:
- - if no given precision, then let mpfr_get_str determine it,
- - if a precision is specified, then one digit before decimal point
- plus SPEC.PREC after it,
- - in order to avoid ambiguity in rounding, we always output one
- binary digit after decimal point even if SPEC.PREC == 0. */
- nsd = (spec.prec < 0) ? 0 : (spec.prec > 0) ? spec.prec + 1 : 2;
- raw_str = mpfr_get_str (0, &exp, 2, nsd, p, spec.rnd_mode);
- raw_str_cur = raw_str;
-
- /* EXP is the exponent for decimal point BEFORE the first digit, we want
- the exponent for decimal point AFTER the first digit */
- exp--;
-
- /* Compute the number of characters in each part of str */
- nbc.sgn = (MPFR_SIGN (p) < 0) || (spec.showsign) || (spec.space)
- ? 1 : 0;
-
- if (spec.prec < 0)
- {
- size_t ndigits;
- char *end;
-
- /* raw_str contains the sign if negative, the first digit that will
- be printed before the decimal point and all other digits are in
- the fractional part */
- ndigits = strlen (raw_str);
- ndigits -= (MPFR_SIGN (p) < 0) ? 2 : 1;
- /* we remove the trailing zeros if any */
- for (end = raw_str + strlen (raw_str) - 1;
- (*end == '0') && (ndigits > 0); --end)
- --ndigits;
-
- if (ndigits > INT_MAX)
- /* overflow error */
- {
- mpfr_free_str (raw_str);
- return -1;
- }
- else
- nbc.frac_part = (int) ndigits;
- }
- else
- nbc.frac_part = spec.prec == 0 ? 1 : spec.prec;
- nbc.point = 1;
- /* the exp_part contains the character 'p' plus the sign character
- plus (exp == 0) ? 1 : floor(log10(abs(exp))) + 1 digits.
- We assume that |exp| < 10^INT_MAX. */
- nbc.exp_part = 3;
- {
- mp_exp_unsigned_t x;
-
- x = SAFE_ABS (mp_exp_unsigned_t, exp);
- while (x > 9)
- {
- nbc.exp_part++;
- x /= 10;
- }
- }
- /* Number of characters to be printed */
- nbc.total = nbc.sgn + nbc.point + nbc.frac_part + nbc.exp_part;
- /* optional leading zeros are counted in int_part */
- if ((spec.left == 0) && (spec.pad == '0') && (nbc.total < spec.width))
- nbc.int_part = spec.width - nbc.total;
- else
- nbc.int_part = 1;
- nbc.total += nbc.int_part;
-
- if ((nbc.total < 0) || (nbc.total > MAX_CHAR_BY_SPEC))
- /* This happens when spec.width, spec.prec, or nbc.exp_part are too
- close to MAX_CHAR_BY_SPEC */
- {
- mpfr_free_str (raw_str);
- return -1;
- }
-
- str = (char *) (*__gmp_allocate_func) (nbc.total + 1);
- str[0] = '\0';
-
- /* Build str from raw_str */
- /* sign */
- if (nbc.sgn != 0)
- {
- if (MPFR_SIGN (p) < 0)
- {
- strcat (str, "-");
- ++raw_str_cur;
- }
- else if (spec.showsign)
- strcat (str, "+");
- else if (spec.space)
- strcat (str, " ");
- }
- /* optional padding with leading zeros */
- {
- int i;
- for (i = 1; i < nbc.int_part; i++)
- strcat (str, "0");
- }
- /* first digit */
- {
- char d[2];
- d[0] = *raw_str_cur++;
- d[1] = '\0';
- strcat (str, d);
- }
- strcat (str, d_point);
- /* fractional part */
- {
- char c;
-
- /* Some trailing zeros may be not taken into account */
- c = raw_str_cur[nbc.frac_part];
- raw_str_cur[nbc.frac_part] = '\0';
- strcat (str, raw_str_cur);
- /* we need to replace raw_str in its initial state in order to be
- correctly freed by mpfr_free_str */
- raw_str_cur[nbc.frac_part] = c;
- }
- /* exponent part */
- {
- char exp_fmt[8];
- char *exp_str;
-
- exp_fmt[0] = 'p';
- exp_fmt[1] = '\0';
- strcat (exp_fmt, "%+.1" MPFR_EXP_FORMAT_SPEC);
- exp_str = (char *) (*__gmp_allocate_func) (nbc.exp_part + 1);
-#if (__GMP_MP_SIZE_T_INT == 1)
- MPFR_ASSERTN (exp >= INT_MIN);
- MPFR_ASSERTN (exp <= INT_MAX);
-#elif (__GMP_MP_SIZE_T_INT == 0)
- MPFR_ASSERTN (exp >= LONG_MIN);
- MPFR_ASSERTN (exp <= LONG_MAX);
-#else
-#error "mp_exp_t size not supported"
-#endif
- if (sprintf (exp_str, exp_fmt, exp) < 0)
- {
- (*__gmp_free_func) (exp_str, nbc.exp_part + 1);
- mpfr_free_str (raw_str);
- (*__gmp_free_func) (str, nbc.total + 1);
-
- return -1;
- }
- strcat (str, exp_str);
- (*__gmp_free_func) (exp_str, nbc.exp_part + 1);
- }
-
- mpfr_free_str (raw_str);
- MPFR_ASSERTD (nbc.total == strlen (str));
- }
-
- /* right justification padding */
- if ((spec.left == 0) && (spec.width > nbc.total))
- buffer_pad (buf, ' ', spec.width - nbc.total);
-
- buffer_cat (buf, str, nbc.total);
-
- /* left justification padding */
- if ((spec.left == 1) && (spec.width > nbc.total))
- buffer_pad (buf, ' ', spec.width - nbc.total);
-
- mpfr_free_str (str);
- return nbc.total;
-}
-
/* struct for easy string clearing */
struct string_list
{
@@ -1377,6 +663,9 @@ struct number_parts
char sign; /* Sign character */
+ char *prefix_ptr; /* Pointer to prefix part */
+ int prefix_size; /* number of characters in *prefix_ptr */
+
char *ip_ptr; /* Pointer to integral part characters*/
int ip_size; /* Number of digits in *ip_ptr */
int ip_trailing_zeros; /* Number of additional null digits in integral
@@ -1400,7 +689,252 @@ struct number_parts
};
/* Determine the different parts of the string representation of the regular
- number p when spec.spec is 'e', 'E', 'g', or 'G'.
+ number p when spec.spec is 'a', 'A', or 'b'.
+ return -1 if some field > MAX_CHAR_BY_SPEC */
+static int
+regular_ab (struct number_parts *np, mpfr_srcptr p,
+ const struct printf_spec spec)
+{
+ int uppercase;
+ int base;
+ char *str;
+ mp_exp_t exp;
+
+ uppercase = spec.spec == 'A';
+
+ /* sign */
+ if (MPFR_IS_NEG (p))
+ np->sign = '-';
+ else if (spec.showsign || spec.space)
+ np->sign = spec.showsign ? '+' : ' ';
+
+ if (spec.spec == 'a' || spec.spec == 'A')
+ /* prefix part */
+ {
+ np->prefix_size = 2;
+ str = (char *) (*__gmp_allocate_func) (1 + np->prefix_size);
+ str[0] = '0';
+ str[1] = uppercase ? 'X' : 'x';
+ str[2] = '\0';
+ np->prefix_ptr = register_string (np->sl, str);
+ }
+
+ /* integral part */
+ np->ip_size = 1;
+ base = (spec.spec == 'b') ? 2 : 16;
+
+ if (spec.spec == 'b' || spec.prec != 0)
+ /* In order to avoid ambiguity in rounding to even case, we will ever
+ output at least one fractional digit in binary mode */
+ {
+ int nsd;
+
+ /* Number of significant digits:
+ - if no given precision, let mpfr_get_str determine it;
+ - if a zero precision is specified and if we are in binary mode, then
+ ask for two binary digits, one before decimal point, and one after;
+ - if a non-zero precision is specified, then one digit before decimal
+ point plus SPEC.PREC after it. */
+ nsd = spec.prec < 0 ? 0
+ : (spec.prec == 0 && spec.spec == 'b') ? 2 : spec.prec + np->ip_size;
+ str = mpfr_get_str (0, &exp, base, nsd, p, spec.rnd_mode);
+ register_string (np->sl, str);
+ np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */
+
+ if (base == 16)
+ /* EXP is the exponent for radix sixteen with decimal point BEFORE the
+ first digit, we want the exponent for radix two and the decimal
+ point AFTER the first digit. */
+ exp = (exp - 1) * 4;
+ else
+ /* EXP is the exponent for decimal point BEFORE the first digit, we
+ want the exponent for decimal point AFTER the first digit. */
+ --exp;
+ }
+ else
+ /* One hexadecimal digit is sufficient but mpfr_get_str returns at least
+ two digits when the base is a power of two.
+ So, in order to avoid double rounding, we will build our own string. */
+ {
+ mp_limb_t *pm = MPFR_MANT (p);
+ mp_size_t ps;
+ int digit, shift;
+ int rnd_away;
+
+ /* rnd_away:
+ 1 if round away from zero,
+ 0 if round to zero,
+ -1 if not decided yet. */
+ rnd_away =
+ spec.rnd_mode == GMP_RNDD ? MPFR_IS_NEG (p) :
+ spec.rnd_mode == GMP_RNDU ? MPFR_IS_POS (p) :
+ spec.rnd_mode == GMP_RNDZ ? 0 : -1;
+
+ /* exponent for radix-2 with the decimal point after the first
+ hexadecimal digit */
+ exp = MPFR_GET_EXP (p) - 4; /* FIXME: possible overflow */
+
+ /* Determine the radix-16 digit by grouping the 4 first digits. Even
+ if MPFR_PREC (p) < 4, we can read 4 bits in its first limb */
+ shift = BITS_PER_MP_LIMB - 4;
+ ps = (MPFR_PREC (p) - 1) / BITS_PER_MP_LIMB;
+ digit = pm[ps]>>shift;
+
+ if (MPFR_PREC (p) > 4)
+ /* round taking into account bits outside the first 4 ones */
+ {
+ if (rnd_away == -1)
+ /* Round to nearest mode: we have to decide in that particular
+ case if we have to round away from zero or not */
+ {
+ mp_limb_t limb, rb, mask;
+
+ /* compute rounding bit */
+ mask = MPFR_LIMB_ONE << (shift - 1);
+ rb = pm[ps] & mask;
+ if (rb == 0)
+ rnd_away = 0;
+ else
+ {
+ mask = MPFR_LIMB_MASK (shift);
+ limb = pm[ps] & mask;
+ while ((ps > 0) && (limb == 0))
+ limb = pm[--ps];
+ if (limb == 0)
+ /* tie case, round to even */
+ rnd_away = (digit & 1) ? 1 : 0;
+ else
+ rnd_away = 1;
+ }
+ }
+
+ if (rnd_away == 1)
+ {
+ digit++;
+ if (digit > 15)
+ /* As we want only the first significant digit, we have
+ to shift one position to the left */
+ {
+ digit >>= 1;
+ ++exp; /* no possible overflow because
+ exp == EXP(p)-3 */
+ }
+ }
+ }
+
+ MPFR_ASSERTD ((0 <= digit) && (digit <= 15));
+ np->ip_size = 1;
+ str = (char *)(*__gmp_allocate_func) (1 + np->ip_size);
+ str[0] = num_to_text [digit];
+ str[1] = '\0';
+
+ np->ip_ptr = register_string (np->sl, str);
+ }
+
+ if (uppercase)
+ /* All digits in upper case */
+ {
+ char *s1 = str;
+ while (*s1)
+ {
+ switch (*s1)
+ {
+ case 'a':
+ *s1 = 'A';
+ break;
+ case 'b':
+ *s1 = 'B';
+ break;
+ case 'c':
+ *s1 = 'C';
+ break;
+ case 'd':
+ *s1 = 'D';
+ break;
+ case 'e':
+ *s1 = 'E';
+ break;
+ case 'f':
+ *s1 = 'F';
+ break;
+ }
+ s1++;
+ }
+ }
+
+ if (spec.spec == 'b' || spec.prec != 0)
+ /* compute the number of digits in fractional part */
+ {
+ char *ptr;
+ size_t str_len;
+
+ /* the sign has been skipped, skip also the first digit */
+ ++str;
+ str_len = strlen (str);
+ ptr = str + str_len - 1; /* points to the end of str */
+
+ if (spec.prec < 0)
+ /* remove trailing zeros, if any */
+ {
+ while ((*ptr == '0') && str_len)
+ {
+ --ptr;
+ --str_len;
+ }
+ }
+
+ if (str_len > INT_MAX || str_len > MAX_CHAR_BY_SPEC)
+ /* too much digits in fractional part */
+ return -1;
+
+ if (str_len)
+ /* there are some non-zero digits in fractional part */
+ {
+ np->fp_ptr = str;
+ np->fp_size = (int) str_len;
+ if ((int) str_len < spec.prec)
+ np->fp_trailing_zeros = spec.prec - str_len;
+ }
+ }
+
+ /* decimal point */
+ if (np->fp_size || spec.alt)
+ np->point = MPFR_DECIMAL_POINT;
+
+ /* the exponent part contains the character 'p', or 'P' plus the sign
+ character plus at least one digit and only as many more digits as
+ necessary to represent the exponent.
+ We assume that |EXP| < 10^INT_MAX. */
+ np->exp_size = 3;
+ {
+ mp_exp_unsigned_t x;
+
+ x = SAFE_ABS (mp_exp_unsigned_t, exp);
+ while (x > 9)
+ {
+ np->exp_size++;
+ x /= 10;
+ }
+ }
+ str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
+ np->exp_ptr = register_string (np->sl, str);
+ {
+ char exp_fmt[8]; /* contains at most 7 characters like in "p%+.1i",
+ or "P%+.2li" */
+
+ exp_fmt[0] = uppercase ? 'P' : 'p';
+ exp_fmt[1] = '\0';
+ strcat (exp_fmt, "%+.1" MPFR_EXP_FORMAT_SPEC);
+
+ if (sprintf (str, exp_fmt, exp) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Determine the different parts of the string representation of the regular
+ number p when spec.spec is 'e', 'E', 'g', or 'G'.
return -1 if some field > MAX_CHAR_BY_SPEC */
static int
@@ -1408,11 +942,10 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
const struct printf_spec spec)
{
int uppercase;
- int nsd;
- char * str;
+ char *str;
mp_exp_t exp;
- uppercase = spec.spec == 'E' || spec.spec == 'F' || spec.spec == 'G';
+ uppercase = spec.spec == 'E' || spec.spec == 'G';
/* sign */
if (MPFR_IS_NEG (p))
@@ -1420,17 +953,22 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
else if (spec.showsign || spec.space)
np->sign = spec.showsign ? '+' : ' ';
- /* Number of significant digits:
- - if no given precision, then let mpfr_get_str determine it,
- - if a precision is specified, then one digit before decimal point
- plus SPEC.PREC after it.
- We use the fact here that mpfr_get_exp allows us to ask for one only
- significant digit when the base is not a power of 2. */
+ /* integral part */
np->ip_size = 1;
- nsd = (spec.prec < 0) ? 0 : spec.prec + np->ip_size;
- str = mpfr_get_str (0, &exp, 10, nsd, p, spec.rnd_mode);
+ {
+ int nsd;
+
+ /* Number of significant digits:
+ - if no given precision, then let mpfr_get_str determine it,
+ - if a precision is specified, then one digit before decimal point
+ plus SPEC.PREC after it.
+ We use the fact here that mpfr_get_exp allows us to ask for only one
+ significant digit when the base is not a power of 2. */
+ nsd = (spec.prec < 0) ? 0 : spec.prec + np->ip_size;
+ str = mpfr_get_str (0, &exp, 10, nsd, p, spec.rnd_mode);
+ }
register_string (np->sl, str);
- np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skeep sign if any */
+ np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */
if (spec.prec != 0)
/* compute the number of digits in fractional part */
@@ -1446,7 +984,7 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
if ((spec.prec < 0)
&& ((spec.spec != 'g' && spec.spec != 'G') || !spec.alt))
/* remove trailing zeros, if any */
- {
+ {
while ((*ptr == '0') && str_len)
{
--ptr;
@@ -1472,11 +1010,11 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
if (np->fp_size || spec.alt)
np->point = MPFR_DECIMAL_POINT;
- /* EXP is the exponent for decimal point BEFORE the first digit, we want the
- exponent for decimal point AFTER the first digit */
+ /* EXP is the exponent for decimal point BEFORE the first digit, we want
+ the exponent for decimal point AFTER the first digit. */
exp--;
- /* the exponent part contains the character 'e' or 'E' plus the sign
+ /* the exponent part contains the character 'e', or 'E' plus the sign
character plus at least two digits and only as many more digits as
necessary to represent the exponent.
We assume that |EXP| < 10^INT_MAX. */
@@ -1498,11 +1036,12 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
np->exp_ptr = register_string (np->sl, str);
{
- char exp_fmt[8]; /* e.g. "e%+.2i" or "E%+.2li" */
+ char exp_fmt[8]; /* e.g. "e%+.2i", or "E%+.2li" */
exp_fmt[0] = uppercase ? 'E' : 'e';
exp_fmt[1] = '\0';
strcat (exp_fmt, "%+.2" MPFR_EXP_FORMAT_SPEC);
+
if (sprintf (str, exp_fmt, exp) < 0)
return -1;
}
@@ -1564,7 +1103,8 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
/* integral part, one digit: "0" */
np->ip_size = 1;
str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, "0");
+ str[0] = '0';
+ str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
/* decimal point */
@@ -1573,9 +1113,9 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
mpfr_log10 (x, x, GMP_RNDD);
mpfr_floor (x, x);
mpfr_abs (x, x, GMP_RNDD);
- /* We have rounded away from zero so that x == |e| (with
- p = m*10^e, see above). Now, x is the number of digits in the
- fractional part. */
+ /* We have rounded away from zero so that x == |e| (with p = m*10^e,
+ see above). Now, x is the number of digits in the fractional
+ part. */
if ((spec.prec > 0) && (mpfr_cmp_si (x, spec.prec + 1) > 0))
/* p is too small for the given precision,
@@ -1616,9 +1156,9 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
np->fp_leading_zeros = spec.prec - 1;
np->fp_size = 1;
-
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, "1");
+ str = (char *) (*__gmp_allocate_func) (1 + np->fp_size);
+ str[0] = '1';
+ str[1] = '\0';
np->fp_ptr = register_string (np->sl, str);
}
else
@@ -1626,8 +1166,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
np->fp_leading_zeros = spec.prec;
}
else
- /* some significant digits can be output in the fractional
- part */
+ /* some significant digits can be output in the fractional part */
{
int n;
int nsd;
@@ -1651,7 +1190,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
if (!keep_trailing_zeros)
/* remove trailing zeros, if any */
- {
+ {
while ((*str == '0') && str_len)
{
--str;
@@ -1706,7 +1245,8 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
/* integral part only */
np->ip_size = 1;
str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, rnd_away ? "1" : "0");
+ str[0] = rnd_away ? '1' : '0';
+ str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
if (spec.alt)
@@ -1723,8 +1263,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
mpfr_floor (x, x);
mpfr_add_ui (x, x, 1, GMP_RNDZ);
/* We have rounded towards zero so that x == e + 1 (with p = m*10^e,
- see above). x is now the number of digits in the integral part.
- */
+ see above). x is now the number of digits in the integral part. */
if (mpfr_cmp_si (x, MAX_CHAR_BY_SPEC) > 0)
/* P is too large to print all its integral part digits */
@@ -1738,7 +1277,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
nsd = spec.prec < 0 ? 0 : spec.prec + np->ip_size;
str = mpfr_get_str (NULL, &exp, 10, nsd, p, spec.rnd_mode);
register_string (np->sl, str);
- np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* remove the sign */
+ np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign */
if (nsd == 0)
/* compute how much non-zero digits in integral and fractional
@@ -1760,12 +1299,12 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
char *ptr;
ptr = str + str_len - 1; /* points to the end of str */
- str_len -= np->ip_size; /* number of digits in fractional
- part */
+ str_len -= np->ip_size; /* number of digits in fractional
+ part */
if (!keep_trailing_zeros)
/* remove trailing zeros, if any */
- {
+ {
while ((*ptr == '0') && str_len)
{
--ptr;
@@ -1831,6 +1370,8 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
np->pad_type = spec.left ? RIGHT : spec.pad == '0' ? LEADING_ZEROS : LEFT;
np->pad_size = 0;
np->sign = '\0';
+ np->prefix_ptr =NULL;
+ np->prefix_size = 0;
np->ip_ptr = NULL;
np->ip_size = 0;
np->ip_trailing_zeros = 0;
@@ -1845,7 +1386,8 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
(*__gmp_allocate_func) (sizeof (struct string_list));
init_string_list (np->sl);
- uppercase = spec.spec == 'E' || spec.spec == 'F' || spec.spec == 'G';
+ uppercase = spec.spec == 'A' || spec.spec == 'E' || spec.spec == 'F'
+ || spec.spec == 'G';
if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (p)))
{
@@ -1906,10 +1448,22 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
else if (spec.showsign || spec.space)
np->sign = spec.showsign ? '+' : ' ';
+ if (spec.spec == 'a' || spec.spec == 'A')
+ /* prefix part */
+ {
+ np->prefix_size = 2;
+ str = (char *) (*__gmp_allocate_func) (1 + np->prefix_size);
+ str[0] = '0';
+ str[1] = uppercase ? 'X' : 'x';
+ str[2] = '\0';
+ np->prefix_ptr = register_string (np->sl, str);
+ }
+
/* integral part */
np->ip_size = 1;
str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, "0");
+ str[0] = '0';
+ str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
if (spec.prec > 0)
@@ -1920,11 +1474,17 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
}
else if (spec.alt)
np->point = MPFR_DECIMAL_POINT;
- if (spec.spec == 'e' || spec.spec == 'E')
+
+ if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b'
+ || spec.spec == 'e' || spec.spec == 'E')
+ /* exponent part */
{
- np->exp_size = 4;
+ np->exp_size = (spec.spec == 'e' || spec.spec == 'E') ? 4 : 3;
str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
- strcpy (str, uppercase ? "E+00" : "e+00");
+ if (spec.spec == 'e' || spec.spec == 'E')
+ strcpy (str, uppercase ? "E+00" : "e+00");
+ else
+ strcpy (str, uppercase ? "P+0" : "p+0");
np->exp_ptr = register_string (np->sl, str);
}
}
@@ -1932,7 +1492,12 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
else
/* regular p, p != 0 */
{
- if (spec.spec == 'f' || spec.spec == 'F')
+ if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b')
+ {
+ if (regular_ab (np, p, spec))
+ goto error;
+ }
+ else if (spec.spec == 'f' || spec.spec == 'F')
{
if (regular_fg (np, p, spec))
goto error;
@@ -1948,7 +1513,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
/* Replace 'g'/'G' by 'e'/'E' or 'f'/'F' following the C99 rules:
if P > X >= -4 then the conversion is with style 'f'/'F' and
precision P-(X+1).
- otherwise, the conversion is with style 'e'/'E' and
+ otherwise, the conversion is with style 'e'/'E' and
precision P-1.
where P is the threshold computed below and X is the exponent
that would be displayed with style 'e'. */
@@ -1982,6 +1547,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
/* compute the number of characters to be written verifying it is not too
much */
total = np->sign ? 1 : 0;
+ total += np->prefix_size;
total += np->ip_size;
if (total < 0 || total > MAX_CHAR_BY_SPEC)
goto error;
@@ -2020,13 +1586,21 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
return -1;
}
-/* sprnt_fp prints a mpfr_t in "%f", "%F", "%g", and "%G" cases.
+/* sprnt_fp prints a mpfr_t according to spec.spec specification.
return the size of the string (not counting the terminating '\0')
return -1 if the built string is too long (i.e. has more than
MAX_CHAR_BY_SPEC characters). */
-static void
-sprnt_fp (struct string_buffer *buf, const struct number_parts np)
+static int
+sprnt_fp (struct string_buffer *buf, mpfr_srcptr p,
+ const struct printf_spec spec)
{
+ int length;
+ struct number_parts np;
+
+ length = partition_number (&np, p, spec);
+ if (length < 0)
+ return -1;
+
/* right justification padding with left spaces */
if (np.pad_type == LEFT && np.pad_size)
buffer_pad (buf, ' ', np.pad_size);
@@ -2035,6 +1609,10 @@ sprnt_fp (struct string_buffer *buf, const struct number_parts np)
if (np.sign)
buffer_pad (buf, np.sign, 1);
+ /* prefix part */
+ if (np.prefix_ptr)
+ buffer_cat (buf, np.prefix_ptr, np.prefix_size);
+
/* right justification padding with leading zeros */
if (np.pad_type == LEADING_ZEROS && np.pad_size)
buffer_pad (buf, '0', np.pad_size);
@@ -2070,6 +1648,9 @@ sprnt_fp (struct string_buffer *buf, const struct number_parts np)
/* left justication padding with right spaces */
if (np.pad_type == RIGHT && np.pad_size)
buffer_pad (buf, ' ', np.pad_size);
+
+ clear_string_list (np.sl);
+ return length;
}
int
@@ -2169,8 +1750,11 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
/* Format processing */
if (spec.spec == '\0')
+ /* end of the format string */
break;
else if (spec.spec == 'n')
+ /* put the number of characters written so far in the location pointed
+ by the next va_list argument */
{
int *int_ptr; /* [TODO] do mp{zqf} cases */
int_ptr = va_arg (ap, int *);
@@ -2181,6 +1765,7 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
*int_ptr = (int) (buf.curr - buf.start);
}
else if (spec.arg_type == MPFR_PREC_ARG)
+ /* output mp_prec_t variable */
{
char *s;
int length;
@@ -2205,10 +1790,10 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
}
}
else if (spec.arg_type == MPFR_ARG)
+ /* output a mpfr_t variable */
{
int length = 0;
mpfr_srcptr p;
- struct number_parts np;
p = va_arg (ap, mpfr_srcptr);
@@ -2229,29 +1814,21 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
break;
case 'a':
case 'A':
- length = sprnt_fp_a (&buf, p, spec);
- break;
case 'b':
- length = sprnt_fp_b (&buf, p, spec);
- break;
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
- length = partition_number (&np, p, spec);
- if (length < 0)
- goto error;
-
- sprnt_fp (&buf, np);
- clear_string_list (np.sl);
+ length = sprnt_fp (&buf, p, spec);
}
if ((length < 0) || ((long)buf.size + length > INT_MAX))
goto error;
}
else
+ /* gmp_printf specification, step forward in the va_list */
{
CONSUME_VA_ARG (spec, ap);
gmp_fmt_flag = 1;