static VALUE bigmul_low_digits(VALUE x, VALUE y, int digits) { int xn = RBIGNUM_LEN(x); if (FIXNUM_P(y)) y = INTVALUE2BIG(y); int yn = RBIGNUM_LEN(y); if (digits > xn + yn) { digits = xn + yn; } VALUE z = rb_big_new(digits, 1); BDIGIT* xds = RBIGNUM_DIGITS(x); BDIGIT* yds = RBIGNUM_DIGITS(y); BDIGIT* zds = RBIGNUM_DIGITS(z); BDIGIT c0,c1,c2; // carry int i, j, k, beg, end; for (k = c0 = c1 = c2 = 0; k < digits; k++) { beg = k >= yn - 1 ? k - yn + 1 : 0; end = k >= xn ? xn - 1 : k; for (i = beg, j = k - beg; i <= end; ++i, --j) MULADD(xds[i], yds[j]); zds[k] = c0; c0 = c1; c1 = c2; c2 = 0; } return rb_big_norm(z); }
static VALUE bug_big_zero(VALUE self, VALUE length) { long len = NUM2ULONG(length); VALUE z = rb_big_new(len, 1); MEMZERO(BIGNUM_DIGITS(z), BDIGIT, len); return z; }
static VALUE bigmul_high_digits(VALUE x, VALUE y, int dontcare, int x_right_shift) { int xn = RBIGNUM_LEN(x); if (FIXNUM_P(y)) y = INTVALUE2BIG(y); int yn = RBIGNUM_LEN(y); BDIGIT* xds = RBIGNUM_DIGITS(x); BDIGIT* yds = RBIGNUM_DIGITS(y); /* in order to avoid rb_big_clone call, let's virtually "shift" x instead of actual shifting */ if (x_right_shift >= xn) { return INT2BIG(0); } else { xds += x_right_shift; xn -= x_right_shift; } int digits = xn + yn; int i, j, k; VALUE z = rb_big_new(digits, 1); BDIGIT* zds = RBIGNUM_DIGITS(z); for (i = 0; i < digits; zds[i++] = 0); int beg, end; BDIGIT c0, c1, c2; for (k = dontcare, c0 = c1 = c2 = 0; k < digits; k++) { beg = k >= yn - 1 ? k - yn + 1 : 0; end = k >= xn ? xn - 1 : k; for (i = beg, j = k - beg; i <= end; ++i, --j) MULADD(xds[i], yds[j]); zds[k] = c0; c0 = c1; c1 = c2; c2 = 0; } return z; }