summaryrefslogtreecommitdiff
path: root/src/vasprintf.c
diff options
context:
space:
mode:
authorthevenyp <thevenyp@280ebfd0-de03-0410-8827-d642c229c3f4>2011-07-28 23:01:52 +0000
committerthevenyp <thevenyp@280ebfd0-de03-0410-8827-d642c229c3f4>2011-07-28 23:01:52 +0000
commitee9bc1f0e107f0d74d46c1eee5c64431b1097884 (patch)
treec10d3b0a8ece9fd24f26672e20123b6b2092a05c /src/vasprintf.c
parenta600bb8356d3ccddd8e4ddb66113c7f1db9523ea (diff)
downloadmpfr-ee9bc1f0e107f0d74d46c1eee5c64431b1097884.tar.gz
Avoid expensive calls to mpfr_get_prec() using mpfr_ceil_mul() instead.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@7761 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'src/vasprintf.c')
-rw-r--r--src/vasprintf.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/src/vasprintf.c b/src/vasprintf.c
index 6d8148b0e..dbfbdc872 100644
--- a/src/vasprintf.c
+++ b/src/vasprintf.c
@@ -805,21 +805,27 @@ struct decimal_info
char *str;
};
-/* For a real non zero number x, what is the exponent f when rounding x after
- rounding with mode r to r(x) = m*10^f, where m has p+1 digits and
- 1 <= m < 10, i.e., 10^f <= round(x,r) < 10^(f+1).
-
- The value of f is put into *e. */
-static void
-round_to_10_power (mpfr_exp_t *e, mpfr_srcptr x, mpfr_prec_t p, mpfr_rnd_t r)
+/* For a real non zero number x, what is the exponent f so that
+ 10^f <= x < 10^(f+1). */
+static mpfr_exp_t
+floor_log10 (mpfr_srcptr x)
{
- char *buf;
+ mpfr_t y;
+ mpfr_exp_t exp;
- buf = mpfr_get_str (NULL, e, 10, p + 1, x, r);
- /* mpfr_get_str corresponds to a significand between 0.1 and 1,
- whereas here we want a significand between 1 and 10. */
- *e = *e - 1;
- mpfr_free_str (buf);
+ /* make sure first that y can represent a mpfr_exp_t exactly
+ and can compare with x */
+ mpfr_prec_t prec = sizeof (mpfr_exp_t) * CHAR_BIT;
+ mpfr_init2 (y, MAX (prec, MPFR_PREC (x)));
+
+ exp = mpfr_ceil_mul (MPFR_GET_EXP (x), 10, 1) - 1;
+ mpfr_set_exp_t (y, exp, MPFR_RNDU);
+ mpfr_ui_pow (y, 10, y, MPFR_RNDU);
+ if (mpfr_cmpabs (x, y) < 0)
+ exp--;
+
+ mpfr_clear (y);
+ return exp;
}
/* Determine the different parts of the string representation of the regular
@@ -1210,7 +1216,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
else
{
/* exp = position of the most significant decimal digit. */
- round_to_10_power (&exp, p, 0, MPFR_RNDZ);
+ exp = floor_log10 (p);
MPFR_ASSERTD (exp < 0);
if (exp < -spec.prec)
@@ -1351,7 +1357,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
size_t nsd; /* Number of significant digits */
/* Determine the position of the most significant decimal digit. */
- round_to_10_power (&exp, p, 0, MPFR_RNDZ);
+ exp = floor_log10 (p);
MPFR_ASSERTD (exp >= 0);
if (exp > INT_MAX)
/* P is too large to print all its integral part digits */
@@ -1360,8 +1366,16 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
np->ip_size = exp + 1;
nsd = spec.prec + np->ip_size;
- str = mpfr_get_str (NULL, &exp, 10, nsd, p, spec.rnd_mode);
- register_string (np->sl, str);
+ if (dec_info == NULL)
+ {
+ str = mpfr_get_str (NULL, &exp, 10, nsd, p, spec.rnd_mode);
+ register_string (np->sl, str);
+ }
+ else
+ {
+ exp = dec_info->exp;
+ str = dec_info->str;
+ }
np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign */
if (spec.group)