[Algorithmic Toolbox学习笔记][week4]Polynomial multiplication

关于多项式的乘法。

假设A = 4526,B = 347,如何求解A * B ?  

常规计算方式

通过小学掌握的知识,我们可以知道用上图中的计算方式可以求出A*B的值。但是,当A和B的数字非常非常大的时候(A/B均大于10位数),这个计算方式就显得冗余和复杂了。

那么为了简便的计算出A*B的结果,我们可以试着用上一课中学到的概念将A和B分解为更小的数字,然后将分解后的数字相乘,最后再把所有结果相加。

用Divide and Conquer来计算

A = 4526 --> 45 | 26 --> A = 45 * 10^2 + 26
B = 347   --> 03 | 47 --> B = 3 * 10^2 + 47

[Algorithmic Toolbox学习笔记][week4]Polynomial multiplication_第1张图片

假设n=数字的位数,那么我们可以推理出以下公式:

A = a * 10^(n/2) + b
B = c * 10^(n/2) + d

A*B = (a * 10^(n/2) + b) * (c * 10^(n/2) + d)
       = (a * 10^(n/2))(c * 10^(n/2)) + ad * 10^(n/2) + bc * 10^(n/2) + bd
       =
ac * 10^2(n/2) + (ad + bc) * 10^(n/2) + bd

因此要计算出A*B的值,我们每次需要做4次乘法,ac, ad, bc, bd.

A = 4526 --> 45 | 26
B = 347 --> 3 | 47

n = 4

-------

ac = 45 * 3 --> 4 | 5 * 0 | 3 --> 0 * 10^2 + (12+0)*10 + 15 = 135

ad = 45 * 47--> 4 | 5 * 4 | 7 --> 16 * 10^2 + (28+20)*10 + 35 = 2115

bc = 26 * 3 --> 2 | 6 * 0 | 3 --> 0 * 10^2 + (6+0)*10 + 18 = 78

bd = 26 * 47 --> 2 | 6 * 4 | 7 --> 8 * 10^2 + (14+24)*10 + 42 = 1222

-------

A*B = ac * 10^4 + (ad + bc) * 10^2 + bd
       = 135*10^4 + (2115 + 78) * 10^2 + 1222
       = 1350000 + 219300 + 1222
       = 1570522

如何再进一步简化,做更少的乘法运算呢?此时我们就要介绍Karatsuba的算法了:

Karatsuba Approach

针对ad + bc,我们需要做两次乘法(a*d和b*c),而Karatsuba提出实际上只需要做一次乘法就可以得ad + bc的结果,即只需要求(a+b)(c+d)

因为:(a+b)(c+d) = ac + ad + bc + bd,再减去 ac 和 bd 后,就等于 ad + bc。(而由于ac和bd是本来就要计算的值,所以实际上只计算了一次乘法即(a+b)*(c+d) )

因此,最后的公式为:

A*B = ac * 10^2(n/2) + ((a+b)(c+d) - ac - bd) * 10^(n/2) + bd

A = 4526 --> 45 | 26
B = 347 --> 3 | 47

n = 4

​​​​​​​-------

ac = 45 * 3 --> 4 | 5 * 0 | 3 --> 0 * 10^2 + (12+0)*10 + 15 = 135

(a+b)(c+d) = 71 * 50 --> 7 | 1 * 5 | 0 --> 35 * 10^2 + (0+5)*10 + 0 = 3550

bd = 26 * 47 --> 2 | 6 * 4 | 7 --> 8 * 10^2 + (14+24)*10 + 42 = 1222

-------

A*B = ac * 10^2(n/2) + ((a+b)(c+d) - ac - bd) * 10^(n/2) + bd
       = 135*10^4 + (3550 - 135 - 1222) * 10^2 + 1222
       = 1350000 + 219300 + 1222
       = 1570522

Implementation

in python3

def karatsuba(A, B):
    if A < 10 or B < 10:
        return A * B
    else:
        n = max(len(str(A)), len(str(B)))
        half = n // 2
        a = A // (10 ** (half))  # left part of A
        b = A % (10 ** (half))  # right part of A
        c = B // (10 ** (half))  # left part of B
        d = B % (10 ** (half))  # right part of B
        ac = karatsuba(a, c)
        bd = karatsuba(b, d)
        ad_plus_bc = karatsuba(a+b, c+d)-ac-bd
        return ac * (10 ** (2 * half)) + (ad_plus_bc * (10 ** half)) + bd

A = int(input('Enter A:'))
B = int(input('Enter B:'))
print('A * B =', karatsuba(A,B))

你可能感兴趣的:(Algorithmic,ToolBox,学习)