ruby-changes:11601
From: matz <ko1@a...>
Date: Tue, 21 Apr 2009 02:53:55 +0900 (JST)
Subject: [ruby-changes:11601] Ruby:r23238 (trunk): * bignum.c (bigsub_int): subtraction without making internal
matz 2009-04-21 02:53:36 +0900 (Tue, 21 Apr 2009) New Revision: 23238 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23238 Log: * 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. Modified files: trunk/ChangeLog trunk/bignum.c Index: ChangeLog =================================================================== --- ChangeLog (revision 23237) +++ ChangeLog (revision 23238) @@ -1,3 +1,14 @@ +Tue Apr 21 01:25:16 2009 Yukihiro Matsumoto <matz@r...> + + * 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 <alexandre.zavorine@n...> * symbian/setup (config.h): added TIMET2NUM and NUM2TIMET to match the change in time.c Index: bignum.c =================================================================== --- bignum.c (revision 23237) +++ bignum.c (revision 23238) @@ -178,7 +178,7 @@ get2comp(x); } -static VALUE +static inline VALUE bigtrunc(VALUE x) { long len = RBIGNUM_LEN(x); @@ -285,7 +285,7 @@ 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 @@ 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<xn; i++) { + } + RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(x)); + zds[0] = -num; + return bignorm(z); + } + zds[0] = BIGLO(num); + num = BIGDN(num); + i = 1; +#else + num = 0; + for (i=0; i<sizeof(y)/sizeof(BDIGIT); i++) { + num += (BDIGIT_DBL_SIGNED)xds[i] - BIGLO(y); + zds[i] = BIGLO(num); + num = BIGDN(num); + y = BIGDN(y); + } +#endif + while (num && i < xn) { + num += xds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } + while (i < xn) { + zds[i] = xds[i]; + i++; + } + if (num < 0) { + z = bigsub(x, rb_int2big(y0)); + } + return bignorm(z); +} + +static VALUE +bigadd_int(VALUE x, long y) +{ + VALUE z; + BDIGIT *xds, *zds; + long xn, zn; + BDIGIT_DBL num; + long i; + + xds = BDIGITS(x); + xn = RBIGNUM_LEN(x); + + if (xn < 2) { + zn = 3; + } + else { + zn = xn + 1; + } + z = bignew(zn, RBIGNUM_SIGN(x)); + zds = BDIGITS(z); + +#if SIZEOF_BDIGITS == SIZEOF_LONG + num = (BDIGIT_DBL)xds[0] + y; + zds[0] = BIGLO(num); + num = BIGDN(num); + i = 1; +#else + num = 0; + for (i=0; i<sizeof(y)/sizeof(BDIGIT); i++) { + num += (BDIGIT_DBL)xds[i] + BIGLO(y); + zds[i] = BIGLO(num); + num = BIGDN(num); + y = BIGDN(y); + } +#endif + while (num && i < xn) { + num += xds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } + if (num) zds[i++] = (BDIGIT)num; + else while (i < xn) { + zds[i] = xds[i]; + i++; + } + assert(i <= zn); + while (i < zn) { + zds[i++] = 0; + } + return bignorm(z); +} + static void bigadd_core(BDIGIT *xds, long xn, BDIGIT *yds, long yn, BDIGIT *zds, long zn) { @@ -1521,10 +1627,22 @@ VALUE rb_big_plus(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 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 @@ 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)); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/