aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-04-26 08:30:10 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-04-26 08:30:10 +0000
commit93bdc98f33c0dfa2d7baf03787f0d8181062d9cf (patch)
treee10bace29abec05970cc226fbe785d91818dc722
parentf70f8173cd9ba0c359d87c0eb10b747f5abd6385 (diff)
downloadruby-93bdc98f33c0dfa2d7baf03787f0d8181062d9cf.tar.gz
* bignum.c (rb_big_pow): reduce multiplying for even number.
* numeric.c (int_pow): calculate power in Fixnum as possible. [ruby-dev:30726] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12223 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog7
-rw-r--r--bignum.c12
-rw-r--r--numeric.c34
3 files changed, 45 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 556419bf54..9520add6e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu Apr 26 17:31:00 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_pow): reduce multiplying for even number.
+
+ * numeric.c (int_pow): calculate power in Fixnum as possible.
+ [ruby-dev:30726]
+
Thu Apr 26 17:18:51 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y: fixes for ripper.
diff --git a/bignum.c b/bignum.c
index aec25c13d9..ba107e9edc 100644
--- a/bignum.c
+++ b/bignum.c
@@ -1552,22 +1552,20 @@ rb_big_pow(VALUE x, VALUE y)
case T_FIXNUM:
yy = FIX2LONG(y);
if (yy > 0) {
- VALUE z = x;
+ VALUE z = (yy & 1) ? x : 0;
if (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024) {
rb_warn("in a**b, b may be too big");
d = (double)yy;
break;
}
- for (;;) {
- yy -= 1;
- if (yy == 0) break;
- while (yy % 2 == 0) {
+ while (yy &= ~1) {
+ do {
yy /= 2;
x = rb_big_mul0(x, x);
if (!BDIGITS(x)[RBIGNUM(x)->len-1]) RBIGNUM(x)->len--;
- }
- z = rb_big_mul0(z, x);
+ } while (yy % 2 == 0);
+ z = z ? rb_big_mul0(z, x) : x;
if (!BDIGITS(z)[RBIGNUM(z)->len-1]) RBIGNUM(z)->len--;
}
return bignorm(z);
diff --git a/numeric.c b/numeric.c
index 756f510ca5..86728f2063 100644
--- a/numeric.c
+++ b/numeric.c
@@ -2259,6 +2259,38 @@ fix_divmod(VALUE x, VALUE y)
}
}
+static VALUE
+int_pow(long x, unsigned long y)
+{
+ int neg = x < 0;
+ long z = 1;
+
+ if (neg) x = -x;
+ if (y & 1) z = x;
+ y &= ~1;
+ do {
+ while (y % 2 == 0) {
+ long x2 = x * x;
+ if (x2 < x || !POSFIXABLE(x2)) {
+ bignum:
+ return rb_big_mul(rb_big_pow(rb_int2big(x), LONG2NUM(y)),
+ rb_int2big(neg ? -z : z));
+ }
+ x = x2;
+ y >>= 1;
+ }
+ {
+ long xz = x * z;
+ if (xz < z || xz < x || !POSFIXABLE(xz)) {
+ goto bignum;
+ }
+ z = xz;
+ }
+ } while (--y);
+ if (neg) z = -z;
+ return LONG2NUM(z);
+}
+
/*
* call-seq:
* fix ** other => Numeric
@@ -2282,7 +2314,7 @@ fix_pow(VALUE x, VALUE y)
if (b == 1) return x;
a = FIX2LONG(x);
if (b > 0) {
- return rb_big_pow(rb_int2big(a), y);
+ return int_pow(a, b);
}
return rb_float_new(pow((double)a, (double)b));
}