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); }
VALUE rb_big_barrett_reduce(VALUE x, VALUE m, VALUE mu, int inplace) { if (!NEGATIVE_P(x) && MORE(m, x)) { return x; } unsigned long len = RBIGNUM_LEN(m); /* >= 1 */ if (FIXNUM_P(x)) { return FIX2LONG(x) >= 0 ? x : rb_big_plus(m, x); } VALUE q = bigmul_high_digits(x, mu, len - 1, len - 1); /* q is not normed */ q = rshift_digits_inplace(q, len + 1); /* [x/m] - 3 <= q <= [x/m] */ q = bigmul_low_digits(q, m, len + 1); /* q is normed */ VALUE a = inplace ? x : rb_big_clone(x); if (RBIGNUM_LEN(a) > (long)len + 1) { RBIGNUM_SET_LEN(a, len + 1); } a = rb_big_minus(a, q); if (NEGATIVE_P(a)) a = ADD(a, power_of_two((len + 1) * BITSPERDIG)); /* a = (x - q * m) mod (base ** (len + 1)) */ while (!MORE(m, a)) /* that is, m <= a */ a = SUB(a, m); return rb_big_norm(a); }
static VALUE gcd_gmp(VALUE x, VALUE y) { return rb_big_norm(rb_gcd_gmp(big(x), big(y))); }
static VALUE gcd_normal(VALUE x, VALUE y) { return rb_big_norm(rb_gcd_normal(rb_to_int(x), rb_to_int(y))); }