summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--src/div.c22
2 files changed, 25 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 558cfe9d1..9fc94bf62 100644
--- a/NEWS
+++ b/NEWS
@@ -47,8 +47,9 @@ Changes from versions 3.1.* to version 3.2.0:
- Improved MPFR manual.
- New MPFRbench program (see the tools/bench directory).
- Speedup in the mpfr_const_euler function (contributed by Fredrik Johansson),
- and in the computation of Bernoulli numbers (used in mpfr_gamma, mpfr_li2,
- mpfr_digamma, mpfr_lngamma and mpfr_lgamma).
+ in the computation of Bernoulli numbers (used in mpfr_gamma, mpfr_li2,
+ mpfr_digamma, mpfr_lngamma and mpfr_lgamma), and in mpfr_div when the
+ divisor has one limb.
- Bug fixes. In particular, a speed improvement when the --enable-assert
or --enable-assert=full configure option is used with GCC.
diff --git a/src/div.c b/src/div.c
index a5c12036b..6e30268e9 100644
--- a/src/div.c
+++ b/src/div.c
@@ -240,6 +240,28 @@ mpfr_div (mpfr_ptr q, mpfr_srcptr u, mpfr_srcptr v, mpfr_rnd_t rnd_mode)
* *
**************************************************************************/
+ /* when the divisor has one limb, we can use mpfr_div_ui, which should be
+ faster, assuming there is no intermediate overflow or underflow.
+ The divisor interpreted as an integer satisfies
+ 2^(GMP_NUMB_BITS-1) <= vm < 2^GMP_NUMB_BITS, thus the quotient
+ satisfies 2^(EXP(u)-1-GMP_NUMB_BITS) < u/vm < 2^(EXP(u)-GMP_NUMB_BITS+1)
+ and its exponent is either EXP(u)-GMP_NUMB_BITS or one more. */
+ if (vsize <= 1 && __gmpfr_emin <= MPFR_EXP(u) - GMP_NUMB_BITS
+ && MPFR_EXP(u) - GMP_NUMB_BITS + 1 <= __gmpfr_emax)
+ {
+ mpfr_exp_t exp_v = MPFR_EXP(v); /* save it in case q=v */
+ if (MPFR_SIGN(v) > 0)
+ inex = mpfr_div_ui (q, u, vp[0], rnd_mode);
+ else
+ {
+ inex = -mpfr_div_ui (q, u, vp[0], MPFR_INVERT_RND(rnd_mode));
+ MPFR_CHANGE_SIGN(q);
+ }
+ /* q did not under/overflow */
+ MPFR_EXP(q) -= exp_v - GMP_NUMB_BITS;
+ return mpfr_check_range (q, inex, rnd_mode);
+ }
+
MPFR_TMP_MARK(marker);
/* set sign */