当前位置: 首页 > news >正文

Karatsuba

Karatsuba算法是一种用于大整数乘法运算的高效算法,由Anatoly Karatsuba在1960年提出,它基于分治策略显著降低了大整数乘法的时间复杂度,以下是对该算法详细的介绍:

一、算法背景

在处理大整数乘法时,传统的竖式乘法计算复杂度较高,时间复杂度为 O(n2)O(n^2)O(n2)(其中 nnn 是整数的位数)。例如,两个1000位的整数相乘,按照传统方法需要进行大约 10002=10000001000^2 = 100000010002=1000000 次基本乘法运算,随着整数位数的不断增加,计算量会迅速膨胀。为了更高效地解决大整数乘法问题,Karatsuba算法应运而生,它通过巧妙的数学变换将复杂度降低到了 O(nlog⁡23)≈O(n1.585)O(n^{\log_2 3}) \approx O(n^{1.585})O(nlog23)O(n1.585),极大地提高了计算效率。

二、核心原理

Karatsuba算法的核心思想是分治(Divide and Conquer),通过减少乘法运算的次数来降低整体的时间复杂度,它将两个大整数的乘法运算转化为多个较小整数乘法运算的组合,关键在于把原本需要4次乘法的计算通过数学变换减少为3次乘法。

假设要计算两个大整数 AAABBB 的乘积,设 AAABBB 的位数为 nnn,将它们进行如下拆分(以十进制为例,二进制等其他进制同理,只是基数不同):

m=⌊n/2⌋m = \lfloor n/2 \rfloorm=n/2(向下取整),把 AAA 拆分成 A=A1×10m+A0A = A_1 \times 10^m + A_0A=A1×10m+A0,其中 A1A_1A1AAA 的高 mmm 位部分,A0A_0A0AAA 的低 mmm 位部分;把 BBB 拆分成 B=B1×10m+B0B = B_1 \times 10^m + B_0B=B1×10m+B0,其中 B1B_1B1BBB 的高 mmm 位部分,B0B_0B0BBB 的低 mmm 位部分。

传统方式需要计算4次乘法,即 A1B1A_1B_1A1B1A1B0A_1B_0A1B0A0B1A_0B_1A0B1A0B0A_0B_0A0B0。而Karatsuba算法利用数学技巧,将中间项 A1B0+A0B1A_1B_0 + A_0B_1A1B0+A0B1 进行变换:
A1B0+A0B1=(A1+A0)×(B1+B0)−A1B1−A0B0A_{1}B_{0} + A_{0}B_{1} = (A_{1} + A_{0}) \times (B_{1} + B_{0}) - A_{1}B_{1} - A_{0}B_{0}A1B0+A0B1=(A1+A0)×(B1+B0)A1B1A0B0

这样,只需要计算3次乘法,分别是:

  1. z2=A1×B1z_2 = A_1 \times B_1z2=A1×B1
  2. z0=A0×B0z_0 = A_0 \times B_0z0=A0×B0
  3. z1=(A1+A0)×(B1+B0)z_1 = (A_1 + A_0) \times (B_1 + B_0)z1=(A1+A0)×(B1+B0)

最后再通过以下公式合并得到 A×BA \times BA×B 的结果:

A×B=z2×102m+(z1−z2−z0)×10m+z0A \times B = z_2 \times 10^{2m} + (z_1 - z_2 - z_0) \times 10^m + z_0A×B=z2×102m+(z1z2z0)×10m+z0

三、算法步骤

  1. 基础情况判断(递归终止条件)
    当要相乘的两个整数位数足够小(通常是小于某个预设的较小阈值,比如在实际应用中可以设定为当整数位数小于等于4位或者8位等,根据具体性能和精度需求决定)时,直接使用普通的竖式乘法来计算它们的乘积,因为对于较小的整数,传统乘法的计算开销相对较小,且避免了过多的递归调用等额外开销。

  2. 整数拆分
    对于较大的整数 AAABBB,按照上述核心原理中提到的方式,根据整数当前的位数确定合适的 mmm 值(一般是取位数的一半左右,向下取整确保划分合理),将 AAA 拆分成 A1A_1A1A0A_0A0,将 BBB 拆分成 B1B_1B1B0B_0B0

  3. 递归计算3个子乘积

    • 计算 z2=Karatsuba(A1,B1)z_2 = \text{Karatsuba}(A_1, B_1)z2=Karatsuba(A1,B1),即递归调用Karatsuba算法来计算 A1A_1A1B1B_1B1 的乘积,因为 A1A_1A1B1B_1B1 通常也是较大的整数,需要继续分治处理。
    • 计算 z0=Karatsuba(A0,B0)z_0 = \text{Karatsuba}(A_0, B_0)z0=Karatsuba(A0,B0),同样递归计算 A0A_0A0B0B_0B0 的乘积。
    • 计算 z1=Karatsuba((A1+A0),(B1+B0))z_1 = \text{Karatsuba}((A_1 + A_0), (B_1 + B_0))z1=Karatsuba((A1+A0),(B1+B0)),先计算 A1+A0A_1 + A_0A1+A0B1+B0B_1 + B_0B1+B0 的和,然后再递归调用Karatsuba算法计算它们的乘积。
  4. 合并结果
    按照公式 A×B=z2×102m+(z1−z2−z0)×10m+z0A \times B = z_2 \times 10^{2m} + (z_1 - z_2 - z_0) \times 10^m + z_0A×B=z2×102m+(z1z2z0)×10m+z0,将计算得到的 z2z_2z2z1z_1z1z0z_0z0 以及对应的 101010 的幂次进行运算,合并得到最终 AAABBB 的乘积结果。在这个过程中,可能涉及到进位等处理,要按照相应的进制规则(如十进制满十进一、二进制满二进一)正确处理数字的进位情况,以保证结果的准确性。

四、实例基础

以下以两个十进制整数 A=1234A = 1234A=1234B=5678B = 5678B=5678 为例,展示Karatsuba算法的计算过程(这里为了方便演示,取 m=2m = 2m=2,即将整数拆分成2位一组):

  1. 拆分整数

    • A=12×102+34A = 12 \times 10^2 + 34A=12×102+34,所以 A1=12A_1 = 12A1=12A0=34A_0 = 34A0=34
    • B=56×102+78B = 56 \times 10^2 + 78B=56×102+78,所以 B1=56B_1 = 56B1=56B0=78B_0 = 78B0=78
  2. 计算3个子乘积

    • 计算 z2=A1×B1=12×56z_2 = A_1 \times B_1 = 12 \times 56z2=A1×B1=12×56
      使用传统乘法可得 12×56=67212 \times 56 = 67212×56=672
    • 计算 z0=A0×B0=34×78z_0 = A_0 \times B_0 = 34 \times 78z0=A0×B0=34×78
      通过传统乘法计算得出 34×78=265234 \times 78 = 265234×78=2652
    • 计算 z1=(A1+A0)×(B1+B0)=(12+34)×(56+78)z_1 = (A_1 + A_0) \times (B_1 + B_0) = (12 + 34) \times (56 + 78)z1=(A1+A0)×(B1+B0)=(12+34)×(56+78)
      先算括号内的加法,12+34=4612 + 34 = 4612+34=4656+78=13456 + 78 = 13456+78=134,然后计算乘积 46×134=616446 \times 134 = 616446×134=6164
  3. 合并结果
    根据公式 A×B=z2×102m+(z1−z2−z0)×10m+z0A \times B = z_2 \times 10^{2m} + (z_1 - z_2 - z_0) \times 10^m + z_0A×B=z2×102m+(z1z2z0)×10m+z0,这里 m=2m = 2m=2,代入计算:

直接验证 1234×5678=70066521234 \times 5678 = 70066521234×5678=7006652

以下以两个十进制整数 A=12345678A = 12345678A=12345678B=98765432B = 98765432B=98765432 为例,展示 Karatsuba 算法更进阶的计算过程(这里取 m=4m = 4m=4,即将整数拆分成 4 位一组):

五、实例进阶,递归Karatsuba算法

如果上次分解的结果值任然很大,可以对分解值继续使用Karatsuba算法来进行计算。

1. 拆分整数
  • 对于整数 AAA
    A=1234×104+5678A = 1234 \times 10^4 + 5678A=1234×104+5678,所以 A1=1234A_1 = 1234A1=1234A0=5678A_0 = 5678A0=5678
  • 对于整数 BBB
    B=9876×104+5432B = 9876 \times 10^4 + 5432B=9876×104+5432,所以 B1=9876B_1 = 9876B1=9876B0=5432B_0 = 5432B0=5432
2. 计算 3 个子乘积
  • 计算 z2=A1×B1=1234×9876z_2 = A_1 \times B_1 = 1234 \times 9876z2=A1×B1=1234×9876
    由于这两个数还是较大的 4 位整数,我们继续对其使用 Karatsuba 算法进行拆分(取 m=2m = 2m=2,将 4 位再拆分成 2 位一组)来计算。

    • A1=1234A_1 = 1234A1=1234 拆分:A11=12A_{11} = 12A11=12A10=34A_{10} = 34A10=34(即 A1=12×102+34A_1 = 12 \times 10^2 + 34A1=12×102+34)。
    • B1=9876B_1 = 9876B1=9876 拆分:B11=98B_{11} = 98B11=98B10=76B_{10} = 76B10=76(即 B1=98×102+76B_1 = 98 \times 10^2 + 76B1=98×102+76)。
    • 计算 3 个子子乘积:
      • 计算 z22=A11×B11=12×98z_{22} = A_{11} \times B_{11} = 12 \times 98z22=A11×B11=12×98
        通过传统乘法可得:
        12×98=(10+2)×98=10×98+2×98=980+196=117612 \times 98 = (10 + 2) \times 98 = 10 \times 98 + 2 \times 98 = 980 + 196 = 117612×98=(10+2)×98=10×98+2×98=980+196=1176
      • 计算 z20=A10×B10=34×76z_{20} = A_{10} \times B_{10} = 34 \times 76z20=A10×B10=34×76
        同样使用传统乘法:
        34×76=(30+4)×76=30×76+4×76=2280+304=258434 \times 76 = (30 + 4) \times 76 = 30 \times 76 + 4 \times 76 = 2280 + 304 = 258434×76=(30+4)×76=30×76+4×76=2280+304=2584
      • 计算 z21=(A11+A10)×(B11+B10)=(12+34)×(98+76)z_{21} = (A_{11} + A_{10}) \times (B_{11} + B_{10}) = (12 + 34) \times (98 + 76)z21=(A11+A10)×(B11+B10)=(12+34)×(98+76)
        先算括号内的加法:12+34=4612 + 34 = 4612+34=4698+76=17498 + 76 = 17498+76=174
        然后计算乘积 46×17446 \times 17446×174
        46×174=46×(100+70+4)=46×100+46×70+46×4=4600+3220+184=800446 \times 174 = 46 \times (100 + 70 + 4) = 46 \times 100 + 46 \times 70 + 46 \times 4 = 4600 + 3220 + 184 = 800446×174=46×(100+70+4)=46×100+46×70+46×4=4600+3220+184=8004
    • 合并 z2z_2z2 的结果:
      根据公式 z2=z22×102m+(z21−z22−z20)×10m+z20z_2 = z_{22} \times 10^{2m} + (z_{21} - z_{22} - z_{20}) \times 10^m + z_{20}z2=z22×102m+(z21z22z20)×10m+z20(这里 m=2m = 2m=2),代入计算:
      先算中间项 (z21−z22−z20)(z_{21} - z_{22} - z_{20})(z21z22z20)
      z21−z22−z20=8004−1176−2584=4244z_{21} - z_{22} - z_{20} = 8004 - 1176 - 2584 = 4244z21z22z20=800411762584=4244
      再分别计算各项乘积并相加:
      z22×104=1176×104=11760000z_{22} \times 10^4 = 1176 \times 10^4 = 11760000z22×104=1176×104=11760000
      (z21−z22−z20)×102=4244×102=424400(z_{21} - z_{22} - z_{20}) \times 10^2 = 4244 \times 10^2 = 424400(z21z22z20)×102=4244×102=424400
      z20=2584z_{20} = 2584z20=2584
      最后求和得到 z2z_2z2
      z2=11760000+424400+2584=12186984z_2 = 11760000 + 424400 + 2584 = 12186984z2=11760000+424400+2584=12186984
  • 计算 z0=A0×B0=5678×5432z_0 = A_0 \times B_0 = 5678 \times 5432z0=A0×B0=5678×5432
    同样采用 Karatsuba 算法进行拆分(取 m=2m = 2m=2,将 4 位拆分成 2 位一组)来计算。

    • A0=5678A_0 = 5678A0=5678 拆分:A01=56A_{01} = 56A01=56A00=78A_{00} = 78A00=78(即 A0=56×102+78A_0 = 56 \times 10^2 + 78A0=56×102+78)。
    • B0=5432B_0 = 5432B0=5432 拆分:B01=54B_{01} = 54B01=54B00=32B_{00} = 32B00=32(即 B0=54×102+32B_0 = 54 \times 10^2 + 32B0=54×102+32)。
    • 计算 3 个子子乘积:
      • 计算 z02=A01×B01=56×54z_{02} = A_{01} \times B_{01} = 56 \times 54z02=A01×B01=56×54
        通过传统乘法:
        56×54=(50+6)×54=50×54+6×54=2700+324=302456 \times 54 = (50 + 6) \times 54 = 50 \times 54 + 6 \times 54 = 2700 + 324 = 302456×54=(50+6)×54=50×54+6×54=2700+324=3024
      • 计算 z00=A00×B00=78×32z_{00} = A_{00} \times B_{00} = 78 \times 32z00=A00×B00=78×32
        计算可得:
        78×32=(70+8)×32=70×32+8×32=2240+256=249678 \times 32 = (70 + 8) \times 32 = 70 \times 32 + 8 \times 32 = 2240 + 256 = 249678×32=(70+8)×32=70×32+8×32=2240+256=2496
      • 计算 z01=(A01+A00)×(B01+B00)=(56+78)×(54+32)z_{01} = (A_{01} + A_{00}) \times (B_{01} + B_{00}) = (56 + 78) \times (54 + 32)z01=(A01+A00)×(B01+B00)=(56+78)×(54+32)
        先算括号内的加法:56+78=13456 + 78 = 13456+78=13454+32=8654 + 32 = 8654+32=86
        然后计算乘积 134×86134 \times 86134×86
        134×86=134×(80+6)=134×80+134×6=10720+804=11524134 \times 86 = 134 \times (80 + 6) = 134 \times 80 + 134 \times 6 = 10720 + 804 = 11524134×86=134×(80+6)=134×80+134×6=10720+804=11524
    • 合并 z0z_0z0 的结果:
      根据公式 z0=z02×102m+(z01−z02−z00)×10m+z00z_0 = z_{02} \times 10^{2m} + (z_{01} - z_{02} - z_{00}) \times 10^m + z_{00}z0=z02×102m+(z01z02z00)×10m+z00(这里 m=2m = 2m=2),代入计算:
      先算中间项 (z01−z02−z00)(z_{01} - z_{02} - z_{00})(z01z02z00)
      z01−z02−z00=11524−3024−2496=6004z_{01} - z_{02} - z_{00} = 11524 - 3024 - 2496 = 6004z01z02z00=1152430242496=6004
      再分别计算各项乘积并相加:
      z02×104=3024×104=30240000z_{02} \times 10^4 = 3024 \times 10^4 = 30240000z02×104=3024×104=30240000
      (z01−z02−z00)×102=6004×102=600400(z_{01} - z_{02} - z_{00}) \times 10^2 = 6004 \times 10^2 = 600400(z01z02z00)×102=6004×102=600400
      z00=2496z_{00} = 2496z00=2496
      最后求和得到 z0z_0z0
      z0=30240000+600400+2496=30842896z_0 = 30240000 + 600400 + 2496 = 30842896z0=30240000+600400+2496=30842896
  • 计算 z1=(A1+A0)×(B1+B0)=(1234+5678)×(9876+5432)z_1 = (A_1 + A_0) \times (B_1 + B_0) = (1234 + 5678) \times (9876 + 5432)z1=(A1+A0)×(B1+B0)=(1234+5678)×(9876+5432)
    先算括号内的加法:
    1234+5678=69121234 + 5678 = 69121234+5678=69129876+5432=153089876 + 5432 = 153089876+5432=15308
    然后计算乘积 6912×153086912 \times 153086912×15308,这里我们再次使用 Karatsuba 算法进行拆分(取 m=3m = 3m=3,将 5 位左右的数拆分成 3 位和 2 位一组)来计算。

    • 691269126912 拆分:6912=6×103+9126912 = 6 \times 10^3 + 9126912=6×103+912,即 69121=66912_{1} = 669121=669120=9126912_{0} = 91269120=912
    • 153081530815308 拆分:15308=15×103+30815308 = 15 \times 10^3 + 30815308=15×103+308,即 153081=1515308_{1} = 15153081=15153080=30815308_{0} = 308153080=308
    • 计算 3 个子子乘积:
      • 计算 z12=69121×153081=6×15=90z_{12} = 6912_{1} \times 15308_{1} = 6 \times 15 = 90z12=69121×153081=6×15=90
      • 计算 z10=69120×153080=912×308z_{10} = 6912_{0} \times 15308_{0} = 912 \times 308z10=69120×153080=912×308
        通过传统乘法(过程略)可得 912×308=280896912 \times 308 = 280896912×308=280896
      • 计算 z11=(69121+69120)×(153081+153080)=(6+912)×(15+308)z_{11} = (6912_{1} + 6912_{0}) \times (15308_{1} + 15308_{0}) = (6 + 912) \times (15 + 308)z11=(69121+69120)×(153081+153080)=(6+912)×(15+308)
        先算括号内的加法:6+912=9186 + 912 = 9186+912=91815+308=32315 + 308 = 32315+308=323
        然后计算乘积 918×323918 \times 323918×323(过程略)可得 918×323=296514918 \times 323 = 296514918×323=296514
    • 合并 z1z_1z1 的结果:
      根据公式 z1=z12×102m+(z11−z12−z10)×10m+z10z_1 = z_{12} \times 10^{2m} + (z_{11} - z_{12} - z_{10}) \times 10^m + z_{10}z1=z12×102m+(z11z12z10)×10m+z10(这里 m=3m = 3m=3),代入计算:
      先算中间项 (z11−z12−z10)(z_{11} - z_{12} - z_{10})(z11z12z10)
      z11−z12−z10=296514−90−280896=15528z_{11} - z_{12} - z_{10} = 296514 - 90 - 280896 = 15528z11z12z10=29651490280896=15528
      再分别计算各项乘积并相加:
      z12×106=90×106=90000000z_{12} \times 10^6 = 90 \times 10^6 = 90000000z12×106=90×106=90000000
      (z11−z12−z10)×103=15528×103=15528000(z_{11} - z_{12} - z_{10}) \times 10^3 = 15528 \times 10^3 = 15528000(z11z12z10)×103=15528×103=15528000
      z10=280896z_{10} = 280896z10=280896
      最后求和得到 z1z_1z1
      z1=90000000+15528000+280896=105808896z_1 = 90000000 + 15528000 + 280896 = 105808896z1=90000000+15528000+280896=105808896
3. 合并结果

根据公式 A×B=z2×102m+(z1−z2−z0)×10m+z0A \times B = z_2 \times 10^{2m} + (z_1 - z_2 - z_0) \times 10^m + z_0A×B=z2×102m+(z1z2z0)×10m+z0,这里 m=4m = 4m=4,代入计算:

  • 先计算 z2×108z_2 \times 10^{8}z2×108
    z2×108=12186984×108=1218698400000000z_2 \times 10^{8} = 12186984 \times 10^{8} = 1218698400000000z2×108=12186984×108=1218698400000000
  • 再计算中间项 (z1−z2−z0)(z_1 - z_2 - z_0)(z1z2z0)
    z1−z2−z0=105808896−12186984−30842896=62779016z_1 - z_2 - z_0 = 105808896 - 12186984 - 30842896 = 62779016z1z2z0=1058088961218698430842896=62779016
  • 然后计算中间项乘以 10410^4104
    (z1−z2−z0)×104=62779016×104=627790160000(z_1 - z_2 - z_0) \times 10^4 = 62779016 \times 10^4 = 627790160000(z1z2z0)×104=62779016×104=627790160000
  • 最后加上 z0z_0z0
    z0=30842896z_0 = 30842896z0=30842896

将上述各项相加可得:122497633244289612249763324428961224976332442896

六、时间复杂度分析

传统的大整数乘法时间复杂度为 O(n2)O(n^2)O(n2),而Karatsuba算法通过分治策略和上述的数学变换,每次将大整数分成两半进行处理,其时间复杂度可以表示为递归式 T(n)=3T(n/2)+O(n)T(n) = 3T(n/2) + O(n)T(n)=3T(n/2)+O(n)(其中 O(n)O(n)O(n) 主要来自于加法、减法以及最后的合并操作等开销)。

根据主定理(Master Theorem)等复杂度分析方法,可以得出Karatsuba算法的时间复杂度为 O(nlog⁡23)≈O(n1.585)O(n^{\log_2 3}) \approx O(n^{1.585})O(nlog23)O(n1.585)。这意味着随着整数位数 nnn 的不断增大,Karatsuba算法相比传统乘法在计算效率上的优势会越来越明显,尤其是处理几百位甚至上千位以上的大整数时,能极大地减少计算时间和资源消耗。

七、应用场景

  1. 编程语言中的大整数运算库
    在很多编程语言中,如Java的 BigInteger 类、Python中处理大整数的相关模块等,当涉及到超出基本数据类型所能表示范围的大整数乘法运算时,内部会自动采用类似Karatsuba算法(有些可能还会结合更先进的分治或优化算法)来提高计算效率,确保能够准确且高效地处理大整数的各种数学运算。

  2. 密码学领域
    像RSA加密算法等,在生成密钥对、进行加密和解密操作过程中,经常需要处理非常大的整数(例如几百位甚至上千位的质数等),Karatsuba算法及其衍生的高效大整数乘法算法能够加快这些大整数运算的速度,从而提升整个加密系统的性能,保证密码学操作在合理的时间内完成。

  3. 高精度科学计算
    在一些科学计算场景中,例如天文学中对星系距离等超大数值的精确计算、物理学中微观粒子相关的高精度数值模拟等,需要对大整数进行精确的乘法运算,Karatsuba算法可以帮助科研人员更高效地完成这些计算任务,减少计算时间成本,提高科研效率。

总之,Karatsuba算法凭借其巧妙的分治思想和对乘法次数的优化,在众多需要处理大整数乘法的领域发挥着重要作用,并且也是后续很多更先进大整数运算优化算法的基础。这条消息已经在编辑器中准备就绪。你想如何调整这篇文档?请随时告诉我。

http://www.dtcms.com/a/354183.html

相关文章:

  • 前端工程化与AI融合:构建智能化开发体系
  • 4-4.Python 数据容器 - 字典 dict(字典 dict 概述、字典的定义与调用、字典的遍历、字典的常用方法)
  • CPU 虚拟化之Cpu Models
  • 代码随想录刷题Day43
  • 时间轮定时器HashedWheelTimer
  • WSL设置静态IP
  • window程序打包
  • Libvio网站与客户端访问故障排查指南(专业版)
  • 什么是低空经济?
  • JMeter 5.3 性能测试:文件下载脚本编写与导出文件接收完整指南
  • QT鼠标事件中的QMouseEvent :e
  • 深度学习---卷积神经网络CNN
  • PLC_博图系列☞基本指令”S_ODT:分配接通延时定时器参数并启动“
  • HTML5超详细学习内容
  • 程序(进程)地址空间(1)
  • 基于MATLAB/Simulink的单机带负荷仿真系统搭建
  • LeetCode-23day:技巧经典
  • 疯狂星期四文案网第52天运营日记
  • 野火STM32Modbus主机读取寄存器/线圈失败(二)-解决CRC校验错误
  • 让ai写一个类github首页
  • Web前端之JavaScript时间体系全解析、performance、Date、now
  • Go语言循环性能终极对决:for vs range 深度剖析
  • 如何用Postman做接口测试?
  • k8s中的服务(Service),详细列举
  • JavaSE:类和对象2
  • Redis集群介绍——主从、哨兵、集群
  • 单兵图传设备如何接入指挥中心平台?国标GB/T28181协议的20位ID有何含义?如何进行配置?
  • [手写系列]Go手写db — — 第二版
  • spring-boot-test与 spring-boot-starter-test 区别
  • 前端架构设计模式与AI驱动的智能化演进