diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-05-09 03:16:16 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-05-09 03:16:16 +0000 |
commit | 587035c080a8d3bf7016ee70f4841c1af40d36c0 (patch) | |
tree | 21c90a12c8e972e2374c6d66fe20cfa87016d23f /numeric.c | |
parent | 8dcf078f72152b2d3a409ff8b8b044328b4dce9c (diff) |
* numeric.c (int_pow): calculate power in Fixnum as possible.
[ruby-dev:30726]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@12262 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 36 |
1 files changed, 35 insertions, 1 deletions
@@ -2177,6 +2177,40 @@ fix_divmod(x, y) return rb_num_coerce_bin(x, y); } +static VALUE +int_pow(x, y) + 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 @@ -2201,7 +2235,7 @@ fix_pow(x, 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)); } else if (TYPE(y) == T_FLOAT) { |