From dd54da6edeaa576ece85ec652612a5c93e7a4883 Mon Sep 17 00:00:00 2001 From: matz Date: Mon, 20 Apr 2009 17:53:36 +0000 Subject: * 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23238 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- bignum.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 6 deletions(-) (limited to 'bignum.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)); -- cgit v1.2.3