summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-07-14 13:24:44 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-07-14 13:24:44 +0000
commitb0eacd027a5f45c0135c7fa294bacb8162ae46b9 (patch)
tree2d57f11c630c4a77e809c36f7942deb218ff2a20
parent651f762c17ba23061868a9e83fa7822621d2de86 (diff)
* bignum.c (bary_subb): Support xn < yn.
(bigsub_core): Removed. (bigsub): Don't compare before subtraction. Just subtract and get the two's complement if the subtraction causes a borrow. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41962 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog7
-rw-r--r--bignum.c73
2 files changed, 42 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index 12f7836634d..a20408b265b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Sun Jul 14 22:21:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_subb): Support xn < yn.
+ (bigsub_core): Removed.
+ (bigsub): Don't compare before subtraction. Just subtract and
+ get the two's complement if the subtraction causes a borrow.
+
Sun Jul 14 00:36:03 2013 Tanaka Akira <akr@fsij.org>
* bignum.c (DIGSPERLONG): Unused macro removed.
diff --git a/bignum.c b/bignum.c
index 0585600dd95..dfe5e99c0d3 100644
--- a/bignum.c
+++ b/bignum.c
@@ -1353,21 +1353,33 @@ bary_subb(BDIGIT *zds, size_t zn, BDIGIT *xds, size_t xn, BDIGIT *yds, size_t yn
{
BDIGIT_DBL_SIGNED num;
size_t i;
+ size_t sn;
- assert(yn <= xn);
assert(xn <= zn);
+ assert(yn <= zn);
+
+ sn = xn < yn ? xn : yn;
num = borrow ? -1 : 0;
- for (i = 0; i < yn; i++) {
+ for (i = 0; i < sn; i++) {
num += (BDIGIT_DBL_SIGNED)xds[i] - yds[i];
zds[i] = BIGLO(num);
num = BIGDN(num);
}
- for (; i < xn; i++) {
- if (num == 0) goto num_is_zero;
- num += xds[i];
- zds[i] = BIGLO(num);
- num = BIGDN(num);
+ if (yn <= xn) {
+ for (; i < xn; i++) {
+ if (num == 0) goto num_is_zero;
+ num += xds[i];
+ zds[i] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ }
+ else {
+ for (; i < yn; i++) {
+ num -= yds[i];
+ zds[i] = BIGLO(num);
+ num = BIGDN(num);
+ }
}
if (num == 0) goto num_is_zero;
for (; i < zn; i++) {
@@ -4237,42 +4249,27 @@ rb_big_neg(VALUE x)
return bignorm(z);
}
-static void
-bigsub_core(BDIGIT *xds, long xn, BDIGIT *yds, long yn, BDIGIT *zds, long zn)
-{
- bary_sub(zds, zn, xds, xn, yds, yn);
-}
-
static VALUE
bigsub(VALUE x, VALUE y)
{
- VALUE z = 0;
- long i = RBIGNUM_LEN(x);
- BDIGIT *xds, *yds;
+ VALUE z;
+ BDIGIT *xds, *yds, *zds;
+ long xn, yn, zn;
- /* if x is smaller than y, swap */
- if (RBIGNUM_LEN(x) < RBIGNUM_LEN(y)) {
- z = x; x = y; y = z; /* swap x y */
- }
- else if (RBIGNUM_LEN(x) == RBIGNUM_LEN(y)) {
- xds = BDIGITS(x);
- yds = BDIGITS(y);
- while (i > 0) {
- i--;
- if (xds[i] > yds[i]) {
- break;
- }
- if (xds[i] < yds[i]) {
- z = x; x = y; y = z; /* swap x y */
- break;
- }
- }
- }
+ xn = RBIGNUM_LEN(x);
+ yn = RBIGNUM_LEN(y);
+ zn = xn < yn ? yn : xn;
- z = bignew(RBIGNUM_LEN(x), z==0);
- bigsub_core(BDIGITS(x), RBIGNUM_LEN(x),
- BDIGITS(y), RBIGNUM_LEN(y),
- BDIGITS(z), RBIGNUM_LEN(z));
+ z = bignew(zn, 1);
+
+ xds = BDIGITS(x);
+ yds = BDIGITS(y);
+ zds = BDIGITS(z);
+
+ if (bary_sub(zds, zn, xds, xn, yds, yn)) {
+ bary_2comp(zds, zn);
+ RBIGNUM_SET_NEGATIVE_SIGN(z);
+ }
return z;
}