From a379112975823550ab7b4493d4bd1244a6a1aeb5 Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 26 Apr 2007 15:02:57 +0000 Subject: * bignum.c (rb_big_pow): truncate all zero BDIGITs. [ruby-dev:30733] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12224 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- bignum.c | 54 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) (limited to 'bignum.c') diff --git a/bignum.c b/bignum.c index ba107e9edc..8346433a56 100644 --- a/bignum.c +++ b/bignum.c @@ -90,34 +90,48 @@ rb_big_2comp(VALUE x) /* get 2's complement */ } static VALUE -bignorm(VALUE x) +bigtrunc(VALUE x) { - if (FIXNUM_P(x)) { - return x; - } - else if (TYPE(x) == T_BIGNUM) { - long len = RBIGNUM(x)->len; - BDIGIT *ds = BDIGITS(x); + long len = RBIGNUM(x)->len; + BDIGIT *ds = BDIGITS(x); - while (len-- && !ds[len]) ; - RBIGNUM(x)->len = ++len; + while (len-- && !ds[len]); + RBIGNUM(x)->len = ++len; + return x; +} + +static VALUE +bigfixize(VALUE x) +{ + long len = RBIGNUM(x)->len; + BDIGIT *ds = BDIGITS(x); - if (len*SIZEOF_BDIGITS <= sizeof(VALUE)) { - SIGNED_VALUE num = 0; - while (len--) { - num = BIGUP(num) + ds[len]; + if (len*SIZEOF_BDIGITS <= sizeof(VALUE)) { + SIGNED_VALUE num = 0; + while (len--) { + num = BIGUP(num) + ds[len]; + } + if (num >= 0) { + if (RBIGNUM(x)->sign) { + if (POSFIXABLE(num)) return LONG2FIX(num); } - if (num >= 0) { - if (RBIGNUM(x)->sign) { - if (POSFIXABLE(num)) return LONG2FIX(num); - } - else if (NEGFIXABLE(-(long)num)) return LONG2FIX(-(long)num); + else { + if (NEGFIXABLE(-(long)num)) return LONG2FIX(-(long)num); } } } return x; } +static VALUE +bignorm(VALUE x) +{ + if (!FIXNUM_P(x) && TYPE(x) == T_BIGNUM) { + x = bigfixize(bigtrunc(x)); + } + return x; +} + VALUE rb_big_norm(VALUE x) { @@ -1563,10 +1577,10 @@ rb_big_pow(VALUE x, VALUE y) do { yy /= 2; x = rb_big_mul0(x, x); - if (!BDIGITS(x)[RBIGNUM(x)->len-1]) RBIGNUM(x)->len--; + bigtrunc(x); } while (yy % 2 == 0); z = z ? rb_big_mul0(z, x) : x; - if (!BDIGITS(z)[RBIGNUM(z)->len-1]) RBIGNUM(z)->len--; + bigtrunc(z); } return bignorm(z); } -- cgit v1.2.3