首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

大整數算法系列(十一):Karatsuba 乘法原理與實作詳解

     編輯:關於C語言

動機:打破 O(n²) 的瓶頸

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²),但遞迴開銷使小數反而較慢。

實作關鍵步驟

  1. 切分點:B = min(x.used, y.used) / 2
  2. 拆分高低半部:複製位元到臨時 bignum
  3. 三次遞迴乘法:x0y0、x1y1、(x0+x1)(y0+y1)
  4. 計算中間項:mid = (x0+x1)(y0+y1) - x0y0 - x1y1
  5. 合併結果:z = 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

  • 32 位元基底:通常 32~64 位
  • 64 位元基底:通常 16~32 位
  • 實測調整:太小增加遞迴開銷,太大失去優勢

延伸:Toom-Cook 與 FFT 乘法

實務上,密碼學常用 2048~4096 位,Karatsuba + Comba 混合已足夠。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
演算法切分段數複雜度適用規模
Karatsuba2O(n^1.585)中等 (百~萬位)
Toom-Cook 3-way3O(n^1.465)大 (萬~十萬位)
Toom-Cook 4-way4O(n^1.404)更大
FFT / NTT-O(n log n)極大 (百萬位以上)