diff --git a/ChangeLog b/ChangeLog index d1d9596955..cc046a99b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Tue Apr 21 01:25:16 2009 Yukihiro Matsumoto + + * bignum.c (bigsub_int): subtraction without making internal + bignum values. + + * bignum.c (bigadd_int): ditto for addition. + + * bignum.c (bigtrunc): declare inline. + + * bignum.c (rb_quad_pack): fix condition. + Tue Apr 21 01:13:42 2009 Alexander Zavorine * symbian/setup (config.h): added TIMET2NUM and NUM2TIMET to match the change in time.c diff --git a/bignum.c b/bignum.c index 28b64d9f20..a6589a2531 100644 --- a/bignum.c +++ b/bignum.c @@ -178,7 +178,7 @@ rb_big_2comp(VALUE x) /* get 2's complement */ get2comp(x); } -static VALUE +static inline VALUE bigtrunc(VALUE x) { long len = RBIGNUM_LEN(x); @@ -285,7 +285,7 @@ rb_int2inum(SIGNED_VALUE n) return rb_int2big(n); } -#ifdef HAVE_LONG_LONG +#if SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG void rb_quad_pack(char *buf, VALUE val) @@ -1450,6 +1450,112 @@ bigsub(VALUE x, VALUE y) return z; } +static VALUE bigadd_int(VALUE x, long y); + +static VALUE +bigsub_int(VALUE x, long y0) +{ + VALUE z; + BDIGIT *xds, *zds; + long xn; + BDIGIT_DBL_SIGNED num; + long i, y; + + y = y0; + xds = BDIGITS(x); + xn = RBIGNUM_LEN(x); + + z = bignew(xn, RBIGNUM_SIGN(x)); + zds = BDIGITS(z); + +#if SIZEOF_BDIGITS == SIZEOF_LONG + num = (BDIGIT_DBL_SIGNED)xds[0] - y; + if (xn == 1 && num < 0) { + for (i=0; i 0) != RBIGNUM_SIGN(x)) { + if (n < 0) { + n = -n; + } + return bigsub_int(x, n); + } + if (n < 0) { + n = -n; + } + return bigadd_int(x, n); + case T_BIGNUM: return bignorm(bigadd(x, y, 1)); @@ -1546,10 +1664,22 @@ rb_big_plus(VALUE x, VALUE y) VALUE rb_big_minus(VALUE x, VALUE y) { + long n; + switch (TYPE(y)) { case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - /* fall through */ + n = FIX2LONG(y); + if ((n > 0) != RBIGNUM_SIGN(x)) { + if (n < 0) { + n = -n; + } + return bigadd_int(x, n); + } + if (n < 0) { + n = -n; + } + return bigsub_int(x, n); + case T_BIGNUM: return bignorm(bigadd(x, y, 0));