Loading AI tools
来自维基百科,自由的百科全书
颂哈吉-施特拉森算法(英语:Schönhage–Strassen algorithm)是渐近快速的大整数乘法算法。是由阿诺德·颂哈吉和沃尔克·施特拉森在1971年发明[1]。若针对二个n位元的整数,其运行的位元复杂度,若以大O符号表示,是。算法使用在有2n+1个元素的环上的迭代快速傅里叶变换,这是一种特别的数论转换。
颂哈吉-施特拉森算法是1971年至2007年之间,渐近最快的乘法算法,2007年时有一个新的乘法算法Fürer算法,其渐近复杂度较低[2],不过Fürer算法只有在大到天文数字的程度时,其速度才会比颂哈吉-施特拉森算法快,实务上不会使用Fürer算法(参考银河式算法)。
在实务上,当数字大于2215至2217(十进制下的10,000到40,000位数)时,颂哈吉-施特拉森算法的速度会比较早期的卡拉楚巴算法和图姆-库克算法要快[3][4][5]。GNU多重精度运算库用这个算法计算至少1728至7808个64位元字节的数值(十进制下的33,000至150,000位数),依硬件架构而定[6],有一个用Java实现的颂哈吉-施特拉森算法,可以计算十进制超过74,000位数[7]。
颂哈吉-施特拉森算法的应用包括数学哲学(例如互联网梅森素数大搜索以及计算圆周率近似值),实务的应用包括克罗内克代入,其中将整系数多项式的乘法有效的简化为大数的乘法,GMP-ECM中用此算法来计算Lenstra椭圆曲线分解[8]。
此段会说明颂哈吉-施特拉森算法实现的细节,主要是依Crandall和Pomerance在《Prime Numbers: A Computational Perspective》书中的简介[9]。其中说明的和颂哈吉原始的方法有些差异:其中用离散加权转换(discrete weighted transform)来快速计算负循环卷积。另一个细节资讯的来源是高德纳的《计算机程序设计艺术》[10]。此章节从建立blocks开始,最后会一步一步的说明算法。
假设要将B基底的123和456用直式乘法相乘,B够大,因此计算中不会有进位的情形。结果会是:
1 | 2 | 3 | ||
× | 4 | 5 | 6 | |
6 | 12 | 18 | ||
5 | 10 | 15 | ||
4 | 8 | 12 | ||
4 | 13 | 28 | 27 | 18 |
数列(4, 13, 28, 27, 18)称为二个原始数列(1,2,3)和(4,5,6)的线性卷积(linear convolution)或非循环卷积(acyclic convolution)。只要有二个数列的线性卷积,要算出原数字在十进制以下的乘积就很简单了:只需要处理进位(例如,最右栏的数字,只保留8,将1进到上一栏的27)。此例中可以得到正确的乘积56088。
有另外几种也很有用的卷积。假设输入数列有n个元素(假设3个),线性卷积会有n+n−1个元素,若将最右边的n个元素加上最左边的 n−1个元素,可以产生循环卷积(cyclic convolution):
28 | 27 | 18 | ||
+ | 4 | 13 | ||
28 | 31 | 31 |
若在循环卷积的结果再考虑其进位,所得结果等效于原来两数字的乘积mod Bn − 1。在此例中,103 − 1 = 999,将(28, 31, 31)计算其进位后得到 3141,而3141 ≡ 56088 (mod 999)。
相对的,若将最右边的n个元素减去最左边的n−1个元素,会产生负循环卷积(negacyclic convolution):
28 | 27 | 18 | ||
− | 4 | 13 | ||
28 | 23 | 5 |
若在负循环卷积的结果再考虑其进位,所得结果等效于原来两数字的乘积mod Bn + 1。此例中,103 + 1 = 1001。将(28, 23, 5)计算进位后得到3035,而3035 ≡ 56088 (mod 1001)。负循环卷积可能会有负数,可以用借位的方式消除其负数。
颂哈吉-施特拉森算法和其他以快速傅立叶变换为基础的乘法算法一样,在本质上都是以卷积定理为基础,可以快速的计算二个数列的循环卷积,卷积定理如下:
若依符号表示,可表示如下:
若用快速傅里叶变换(FFT)来计算DFT及IDFT,再用递回的方式处理乘法算法,来将DFT(X)和DFT(Y)相乘,就可以得到计算循环卷积的快速算法。
在此算法中,若计算负循环卷积会更有效:使用修改后的卷积定理版本(参考数论转换)也可以有相同效果。假设向量X和Y的长度是n,而a是2n阶的单位根(意思是a2n = 1,其他a的较小幂次都不等于1),可以定义第三个向量A,称为加权向量:
负循环卷积可以表示为下式:
这和循环卷积的公式类似,只是输入要先乘以A,输出要乘以A−1。
离散傅里叶变换是抽象的运算,因此可以在任意环的代数结构下运作。一般而言是在复数下进行,但实际上为了要有准确的结果,要处理复数运算到足够的精度,这种乘法不但慢,而且容易有错误。因此会用数论转换的方式进行,是在整数模N(N为特定整数)的底下进行。
就像在复数平面上,每一阶都可以找到原根一样,给定任何的阶数n,可以选择适当的N,使得b是在整数模N的系统下,n阶的原根(bn ≡ 1 (mod N),b其他较小的次幂,都不会是1 mod N)。
此算法会花很多时间演算小数字的次幂,若用一个天真的方式来处理算法,这会出现许多次。
颂哈吉-施特拉森算法的关键是选择模数N等于2n + 1,其中的n是要转换件数P=2p的倍数。若标准系统,用二进制的形式表示大数值,有许多的好处:
为了让递回乘法比较方便,会将颂哈吉-施特拉森算法定位为二个数字的乘积mod 2n + 1(n为某整数),而不是一般的乘法。这不会失去算法的一般性,因为可以选择够大的n,使得乘积mod 2n + 1就是乘积本身。
在此算法中,有许多和二个次幂相乘或相除(包括所有的原根)的情形是可以用较小数字的移位和相加达成。原因是因为观察到以下的算式:
其中2n进制下的k位数,若用位值计数法表示,可以写成(dk−1,...,d1,d0),代表数值,针对每一个di可得0 ≤ di < 2n。
因此可以简化表示为二进制数字进行mod 2n + 1的计数:取最右边(最小位)的n位元,减去较高位的n位元,再加上再高位的n位元,一直计算到所有位元都已处理为止。若所得的数超过0到2n的范围,可以加或减模数2n + 1的倍数以进行正规化。例如,若n=3(因此模数是23+1 = 9),要化简的数字是656,可以得到:
甚至,针对很多位元的移位,还有简化的方式。假设数字A介于0到2n之间,希望乘以2k。将k除以n可得到k = qn + r,其中r < n。因此可得:
因为A≤ 2n,且r < n。左移r位元后最多有2n−1位元,因此只需要一次位移和减法(之后可能要正规化)。
最终,若要除以2k,可将此段的第一个式子平方,可得:
因此
此算法有分割、评估(前向FFT)、各项相乘、内插(反FFT)以及合并的阶段,类似Karatsuba算法和Toom-Cook算法。
假设输入数字是x和y,以及整数N,以下算法可以计算xy mod 2N + 1的结果。假设N够大,使得乘积取模数后的结果仍是乘积本身。
输入数字最佳的分割组数和成比例,其中N是输入数字的位元数,此设法会让执行时间的复杂度为O(N log N log log N),[1][9],因此需依规则设定参数k。实务上,会依输入数字大小以及算法架构而定,一般会介于4到16之间[8]。
在步骤2,已观察到以下的现象:
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.