summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--bignum.c20
2 files changed, 24 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 05b44fbdc4..ded56360f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Jun 3 23:47:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bitlength_bdigit): New function.
+ (rb_big_pow): Use bitlength_bdigit instead of ffs.
+
Mon Jun 3 23:11:19 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
* lib/fileutils.rb: fix behavior when mkdir/mkdir_p accepted "/".
diff --git a/bignum.c b/bignum.c
index 96b570a52d..820eff0fb4 100644
--- a/bignum.c
+++ b/bignum.c
@@ -3178,6 +3178,24 @@ bigsqr(VALUE x)
return bigtrunc(bigmul0(x, x));
}
+static int
+bitlength_bdigit(BDIGIT v)
+{
+ if (v == 0)
+ return 0;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+#if 2 < SIZEOF_BDIGITS
+ v |= v >> 16;
+#endif
+ v++;
+ if (v == 0)
+ return SIZEOF_BDIGITS*CHAR_BIT;
+ return ffs(v); /* assumption: sizeof(BDIGIT) <= sizeof(int) */
+}
+
/*
* call-seq:
* big ** exponent -> numeric
@@ -3219,7 +3237,7 @@ rb_big_pow(VALUE x, VALUE y)
VALUE z = 0;
SIGNED_VALUE mask;
const long xlen = RBIGNUM_LEN(x) - 1;
- const long xbits = ffs(RBIGNUM_DIGITS(x)[xlen]) + SIZEOF_BDIGITS*BITSPERDIG*xlen;
+ const long xbits = bitlength_bdigit(RBIGNUM_DIGITS(x)[xlen]) + SIZEOF_BDIGITS*BITSPERDIG*xlen;
const long BIGLEN_LIMIT = BITSPERDIG*1024*1024;
if ((xbits > BIGLEN_LIMIT) || (xbits * yy > BIGLEN_LIMIT)) {