Comba 乘法雖常數小,但時間複雜度仍為 O(n²)。當位數達到數千位以上,耗時急劇增長。Karatsuba 以**分治法**將複雜度降至 O(n^log₂3) ≈ O(n^1.585)。
設兩大整數 X、Y,以基底 B 切成高低兩半:
X = X₁·B + X₀ Y = Y₁·B + Y₀
乘積:
Z = X·Y = X₁Y₁·B² + (X₁Y₀ + X₀Y₁)·B + X₀Y₀
直接計算需 4 次半大小乘法。Karatsuba 觀察到:
X₁Y₀ + X₀Y₁ = (X₁ + X₀)(Y₁ + Y₀) - X₁Y₁ - X₀Y₀
只需 **3 次** 半大小乘法(X₁Y₁、X₀Y₀、(X₁+X₀)(Y₁+Y₀))加上若干加減法與位移。
T(n) = 3·T(n/2) + O(n) → T(n) = O(n^log₂3) ≈ O(n^1.585)
優於 O(n²),但遞迴開銷使小數反而較慢。
B = min(x.used, y.used) / 2bignumx0y0、x1y1、(x0+x1)(y0+y1)mid = (x0+x1)(y0+y1) - x0y0 - x1y1z = x0y0 + (mid << B) + (x1y1 << 2B)static int bn_mul_karatsuba(bignum *z, const bignum *x, const bignum *y) {
size_t B = BN_MIN(x->used, y->used) >> 1; // 切分點
bignum x0, x1, y0, y1, t1, x0y0, x1y1;
// ... 初始化並複製高低半部 ...
bn_mul_bn(x0y0, &x0, &y0); // 遞迴
bn_mul_bn(x1y1, &x1, &y1);
bn_add_abs(&t1, &x0, &x1); // x0+x1
bn_add_abs(&x0, &y0, &y1); // 復用 x0 空間存 y0+y1
bn_mul_bn(&t1, &x0, &t1); // (x0+x1)(y0+y1)
bn_add_abs(&x0, x0y0, x1y1); // x0y0 + x1y1
bn_sub_abs(&t1, &t1, &x0); // mid = (x0+x1)(y0+y1) - x0y0 - x1y1
bn_lshd(&t1, B); // mid << B
bn_lshd(x1y1, B << 1); // x1y1 << 2B
bn_add_abs(&t1, x0y0, &t1); // x0y0 + mid
bn_add_abs(z, &t1, x1y1); // 最終結果
// 清理臨時變數
return 0;
}
KARATSUBA_MUL_CUTOFF| 演算法 | 切分段數 | 複雜度 | 適用規模 |
|---|---|---|---|
| Karatsuba | 2 | O(n^1.585) | 中等 (百~萬位) |
| Toom-Cook 3-way | 3 | O(n^1.465) | 大 (萬~十萬位) |
| Toom-Cook 4-way | 4 | O(n^1.404) | 更大 |
| FFT / NTT | - | O(n log n) | 極大 (百萬位以上) |