算法分析与设计学习中,接触到一道大整数乘法问题,分享出来,原题目如下:
算法分析在用分治法求两个n位大整数u和v的乘积时,将u和v都分割为长度为n/3的3段。证明可以用5次n/3位整数的乘法求得uv的值。按此思想设计大整数乘积的分治方法,并分析算法的计算复杂性。
先参考一道较为简单的题目:设有两个n位二进制数X,Y,求它们的乘积XY。
分析:按照一般算法,根据小学数学乘法规律,两个数中每位数都需要相应做乘法,则需要的时间复杂度是O(n^2)。
此时,我们考虑将X,Y分为高位、低位,即
X = | A| B | , Y = | C| D|
A,B,C,D均为n/2位,求XY的问题可以转换为:
X * Y = (A * 2^(n/2) +B ) *(C * 2^(n/2) +D )
= AC * 2^n + (AD + BC) * 2^(n/2)+BD
则,可以看出利用分治法后,进行了4次n/2位的乘法运算。但是并没有涉及算法性能优化,时间复杂度依然是O(n^2)。
这个算法进行性能提升可以使用如下方法:
先计算
U = (A + B)(C + D), V = AC, W = BD
则 Z = XY = V * 2^n +(U - V- W ) * 2^(n/2) + W
上面过程中,由于只使用了U、V、W涉及的3次乘法,比没有优化的少了一种,时间复杂度就降低到了
具体 过程可以参考 Karatsuba算法
Karatsuba算法伪代码实现如下
procedure karatsuba(num1, num2)
if (num1 < 10) or (num2 < 10)
return num1*num2
/* calculates the size of the numbers */
m = max(size_base10(num1), size_base10(num2))
m2 = m/2
/* split the digit sequences about the middle */
high1, low1 = split_at(num1, m2)
high2, low2 = split_at(num2, m2)
/* 3 calls made to numbers approximately half the size */
z0 = karatsuba(low1,low2)
z1 = karatsuba((low1+high1),(low2+high2))
z2 = karatsuba(high1,high2)
return (z2*10^(2*m2))+((z1-z2-z0)*10^(m2))+(z0)
具体例子可以参照这个图片
那参