mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-bigint: optimize multiplication for power-of-2 numbers
Add fast path for multiplying by powers of 2 (2^n). Uses left shift instead of Karatsuba multiplication: x * 2^n = x << n. This optimizes "mostly-zero" patterns common in fuzzing tests, where numbers like 2^2097150 (single bit set) would otherwise trigger slow Karatsuba multiplication. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1146,6 +1146,32 @@ mpz_all_ones_p(mpz_t *x)
|
||||
return (x->sz - 1) * DIG_SIZE + top_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if x is a power of 2 (2^n).
|
||||
* Returns n if x = 2^n, or 0 otherwise.
|
||||
* This is the "mostly-zero" pattern common in fuzzing tests.
|
||||
*/
|
||||
static size_t
|
||||
mpz_power_of_2_exp(mpz_t *x)
|
||||
{
|
||||
if (x->sn <= 0 || x->sz == 0) return 0;
|
||||
|
||||
/* All limbs except top must be zero */
|
||||
for (size_t i = 0; i + 1 < x->sz; i++) {
|
||||
if (x->p[i] != 0) return 0;
|
||||
}
|
||||
|
||||
/* Top limb must be a power of 2: (v & (v - 1)) == 0 */
|
||||
mp_limb top = x->p[x->sz - 1];
|
||||
if (top == 0 || (top & (top - 1)) != 0) return 0;
|
||||
|
||||
/* Count trailing zeros in top limb to get bit position */
|
||||
size_t bit_pos = 0;
|
||||
while ((top & 1) == 0) { bit_pos++; top >>= 1; }
|
||||
|
||||
return (x->sz - 1) * DIG_SIZE + bit_pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply two "all ones" numbers using algebraic identity:
|
||||
* (2^n - 1) * (2^m - 1) = 2^(n+m) - 2^n - 2^m + 1
|
||||
@@ -1239,6 +1265,18 @@ mpz_mul(mpz_ctx_t *ctx, mpz_t *ww, mpz_t *u, mpz_t *v)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fast path for power of 2: x * 2^n = x << n */
|
||||
size_t u_pow2 = mpz_power_of_2_exp(u);
|
||||
if (u_pow2) {
|
||||
mpz_mul_2exp(ctx, ww, v, u_pow2);
|
||||
return;
|
||||
}
|
||||
size_t v_pow2 = mpz_power_of_2_exp(v);
|
||||
if (v_pow2) {
|
||||
mpz_mul_2exp(ctx, ww, u, v_pow2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!should_use_karatsuba(u->sz, v->sz)) {
|
||||
mpz_mul_basic(ctx, ww, u, v);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user