[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]