summaryrefslogtreecommitdiff
path: root/mpf
diff options
context:
space:
mode:
authorTorbjorn Granlund <torbjorng@google.com>2015-10-30 18:59:45 +0100
committerTorbjorn Granlund <torbjorng@google.com>2015-10-30 18:59:45 +0100
commitcdad7ed97b70d51463143299ffbfa40ade6b98fa (patch)
treee170513ce4663fb4bbccce603227f5ce42b684f6 /mpf
parent562cf0bf7dde1b16ddd9cead0ca1744f0223461c (diff)
downloadgmp-cdad7ed97b70d51463143299ffbfa40ade6b98fa.tar.gz
Add log(e) precision bits.
Diffstat (limited to 'mpf')
-rw-r--r--mpf/pow_ui.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/mpf/pow_ui.c b/mpf/pow_ui.c
index 558addc4b..6d0528bed 100644
--- a/mpf/pow_ui.c
+++ b/mpf/pow_ui.c
@@ -32,6 +32,11 @@ see https://www.gnu.org/licenses/. */
#include "gmp-impl.h"
#include "longlong.h"
+/* This uses a plain right-to-left square-and-multiply algorithm.
+
+ FIXME: When popcount(e) is not too small, it would probably speed things up
+ to use a k-ary sliding window algorithm. */
+
void
mpf_pow_ui (mpf_ptr r, mpf_srcptr b, unsigned long int e)
{
@@ -50,9 +55,11 @@ mpf_pow_ui (mpf_ptr r, mpf_srcptr b, unsigned long int e)
count_leading_zeros (cnt, (mp_limb_t) e);
cnt = GMP_LIMB_BITS - 1 - cnt;
- /* Use a temp for all intermediate result. We might want to add an exponent
- derived # of bits here too, e.g. ((cnt >> GMP_LIMB_BITS/2) != 0). */
- mpf_init2 (t, mpf_get_prec (r) + GMP_LIMB_BITS);
+ /* Increase computation precision as a function of the exponent. Adding
+ log2(popcount(e) + log2(e)) bits should be sufficient, but we add log2(e),
+ i.e. much more. With mpf's rounding of precision to whole limbs, this
+ will be excessive only when limbs are artificially small. */
+ mpf_init2 (t, mpf_get_prec (r) + cnt);
mpf_set (t, b); /* consume most significant bit */
while (--cnt > 0)
@@ -62,6 +69,7 @@ mpf_pow_ui (mpf_ptr r, mpf_srcptr b, unsigned long int e)
mpf_mul (t, t, b);
}
+ /* Do the last iteration specially in order to save a copy operation. */
if (e & 1)
{
mpf_mul (t, t, t);