1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* bignum.c (bigmul1_karatsuba): fix calculation order to prevent

underflow.  [ruby-core:29088]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27425 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
mame 2010-04-20 15:31:46 +00:00
parent adfe4f3930
commit 52998fa591
2 changed files with 23 additions and 15 deletions

View file

@ -1,3 +1,8 @@
Wed Apr 21 00:29:39 2010 Yusuke Endoh <mame@tsg.ne.jp>
* bignum.c (bigmul1_karatsuba): fix calculation order to prevent
underflow. [ruby-core:29088]
Wed Apr 21 00:26:17 2010 Yusuke Endoh <mame@tsg.ne.jp> Wed Apr 21 00:26:17 2010 Yusuke Endoh <mame@tsg.ne.jp>
* compile.c (NODE_NEXT, NODE_REDO): add dummy putnil instruction to * compile.c (NODE_NEXT, NODE_REDO): add dummy putnil instruction to

View file

@ -2077,7 +2077,7 @@ static VALUE
bigmul1_karatsuba(VALUE x, VALUE y) bigmul1_karatsuba(VALUE x, VALUE y)
{ {
long i, n, xn, yn, t1n, t2n; long i, n, xn, yn, t1n, t2n;
VALUE xh, xl, yh, yl, z, t1, t2; VALUE xh, xl, yh, yl, z, t1, t2, t3;
BDIGIT *zds; BDIGIT *zds;
xn = RBIGNUM_LEN(x); xn = RBIGNUM_LEN(x);
@ -2122,24 +2122,19 @@ bigmul1_karatsuba(VALUE x, VALUE y)
/* copy t2 into low bytes of the result (z0) */ /* copy t2 into low bytes of the result (z0) */
MEMCPY(zds, BDIGITS(t2), BDIGIT, t2n); MEMCPY(zds, BDIGITS(t2), BDIGIT, t2n);
for (i = t2n; i < 2 * n; i++) zds[i] = 0; for (i = t2n; i < 2 * n; i++) zds[i] = 0;
/* subtract t2 from middle bytes of the result (z1) */
i = xn + yn - n;
bigsub_core(zds + n, i, BDIGITS(t2), t2n, zds + n, i);
} }
else { else {
t2 = Qundef;
/* copy 0 into low bytes of the result (z0) */ /* copy 0 into low bytes of the result (z0) */
for (i = 0; i < 2 * n; i++) zds[i] = 0; for (i = 0; i < 2 * n; i++) zds[i] = 0;
} }
/* subtract t1 from middle bytes of the result (z1) */
i = xn + yn - n;
bigsub_core(zds + n, i, BDIGITS(t1), t1n, zds + n, i);
/* xh <- xh + xl */ /* xh <- xh + xl */
if (RBIGNUM_LEN(xl) > RBIGNUM_LEN(xh)) { if (RBIGNUM_LEN(xl) > RBIGNUM_LEN(xh)) {
t1 = xl; xl = xh; xh = t1; t3 = xl; xl = xh; xh = t3;
} }
/* xh has a margin for carry */
bigadd_core(BDIGITS(xh), RBIGNUM_LEN(xh), bigadd_core(BDIGITS(xh), RBIGNUM_LEN(xh),
BDIGITS(xl), RBIGNUM_LEN(xl), BDIGITS(xl), RBIGNUM_LEN(xl),
BDIGITS(xh), RBIGNUM_LEN(xh)); BDIGITS(xh), RBIGNUM_LEN(xh));
@ -2147,19 +2142,27 @@ bigmul1_karatsuba(VALUE x, VALUE y)
/* yh <- yh + yl */ /* yh <- yh + yl */
if (x != y) { if (x != y) {
if (RBIGNUM_LEN(yl) > RBIGNUM_LEN(yh)) { if (RBIGNUM_LEN(yl) > RBIGNUM_LEN(yh)) {
t1 = yl; yl = yh; yh = t1; t3 = yl; yl = yh; yh = t3;
} }
/* yh has a margin for carry */
bigadd_core(BDIGITS(yh), RBIGNUM_LEN(yh), bigadd_core(BDIGITS(yh), RBIGNUM_LEN(yh),
BDIGITS(yl), RBIGNUM_LEN(yl), BDIGITS(yl), RBIGNUM_LEN(yl),
BDIGITS(yh), RBIGNUM_LEN(yh)); BDIGITS(yh), RBIGNUM_LEN(yh));
} }
else yh = xh; else yh = xh;
/* t1 <- xh * yh */ /* t3 <- xh * yh */
t1 = bigmul0(xh, yh); t3 = bigmul0(xh, yh);
/* add t1 to middle bytes of the result (z1) */ i = xn + yn - n;
bigadd_core(zds + n, i, BDIGITS(t1), big_real_len(t1), zds + n, i); /* add t3 to middle bytes of the result (z1) */
bigadd_core(zds + n, i, BDIGITS(t3), big_real_len(t3), zds + n, i);
/* subtract t1 from middle bytes of the result (z1) */
bigsub_core(zds + n, i, BDIGITS(t1), t1n, zds + n, i);
/* subtract t2 from middle bytes of the result (z1) */
if (t2 != Qundef) bigsub_core(zds + n, i, BDIGITS(t2), t2n, zds + n, i);
return z; return z;
} }