mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-bigint: Replace binary GCD with Euclidean algorithm in mpz_gcd
The previous implementation of mpz_gcd for multi-limb numbers, commented as "Use Lehmer's algorithm", was in fact an implementation of the binary GCD algorithm (Stein's algorithm). This commit replaces that binary GCD implementation with a standard Euclidean algorithm. For multi-limb numbers, a well-implemented Euclidean algorithm leveraging an optimized modular division (mpz_mod) can be more efficient than the binary GCD. This change provides a clearer and more efficient foundation for GCD calculations, and serves as a stepping stone towards a true Lehmer's algorithm if pursued later. Co-authored-by: Gemini <gemini@google.com>
This commit is contained in:
@@ -2633,38 +2633,14 @@ mpz_gcd(mpz_ctx_t *ctx, mpz_t *gg, mpz_t *aa, mpz_t *bb)
|
||||
mpz_div_2exp(ctx, &a, &a, a_zeros);
|
||||
mpz_div_2exp(ctx, &b, &b, b_zeros);
|
||||
|
||||
/* Use Lehmer's algorithm for large multi-limb numbers (> 3 limbs) */
|
||||
if (a.sz > 3 && b.sz > 3) {
|
||||
mpz_t u0, u1, v0, v1, q, r;
|
||||
mpz_init_temp(ctx, &u0, 2);
|
||||
mpz_init_temp(ctx, &u1, 2);
|
||||
mpz_init_temp(ctx, &v0, 2);
|
||||
mpz_init_temp(ctx, &v1, 2);
|
||||
mpz_init_temp(ctx, &q, 2);
|
||||
mpz_init_temp(ctx, &r, 2);
|
||||
|
||||
while (ucmp(&a, &b) != 0) {
|
||||
if (ucmp(&a, &b) > 0) {
|
||||
mpz_sub(ctx, &a, &a, &b);
|
||||
mpz_div_2exp(ctx, &a, &a, mpz_trailing_zeros(&a));
|
||||
}
|
||||
else {
|
||||
mpz_sub(ctx, &b, &b, &a);
|
||||
mpz_div_2exp(ctx, &b, &b, mpz_trailing_zeros(&b));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (ucmp(&a, &b) != 0) {
|
||||
if (ucmp(&a, &b) > 0) {
|
||||
mpz_sub(ctx, &a, &a, &b);
|
||||
mpz_div_2exp(ctx, &a, &a, mpz_trailing_zeros(&a));
|
||||
}
|
||||
else {
|
||||
mpz_sub(ctx, &b, &b, &a);
|
||||
mpz_div_2exp(ctx, &b, &b, mpz_trailing_zeros(&b));
|
||||
}
|
||||
}
|
||||
/* Euclidean algorithm for multi-limb numbers */
|
||||
while (!zero_p(&b)) {
|
||||
mpz_t temp;
|
||||
mpz_init_temp(ctx, &temp, a.sz);
|
||||
mpz_mod(ctx, &temp, &a, &b);
|
||||
mpz_move(ctx, &a, &b);
|
||||
mpz_move(ctx, &b, &temp);
|
||||
mpz_clear(ctx, &temp);
|
||||
}
|
||||
mpz_mul_2exp(ctx, gg, &a, shift);
|
||||
mpz_clear(ctx, &a);
|
||||
|
||||
Reference in New Issue
Block a user