把 N² 次乘加拆成 2N·log₂N 次
N 拆成两个因子,下标写成两位数,双重求和就能一位一位地求;一直拆到 2,一万个点的变换只要照直算的几百分之一。这一招高斯写过,他们登出来的时候,正好有机器可以跑它。
1965 年 4 月的《计算数学》第 19 卷第 297–301 页,库利与图基的《复傅里叶级数的机器计算算法》只有五页。问题一行写得完:给 N 个复数 A(k),要算 X(j) = Σ A(k)·W 的 jk 次方,W 是 1 的 N 次本原根。照直算,每个 X(j) 要 N 次乘加,一共 N² 次。他们的办法是把 N 拆成 r₁·r₂,把下标 j、k 都写成两位「数字」,那个求和就能先对一位求、再对另一位求:先 N·r₁ 次,再 N·r₂ 次,合计 N(r₁ + r₂)。一直拆下去,N = r₁r₂⋯r_m 时只要 N(r₁ + ⋯ + r_m) 次;N 是 2 的 m 次方时是 2N·log₂N 次,文中说实际还用不了这么多。按二进制拆时,结果的下标要把各位倒过来读,整个计算就在存原数据的那 N 个位置里做完,不用多一块存储。文末是 IBM 7094 上的计时:2 的 13 次方即 8192 个点,最慢的一种排法用了 0.13 分钟。照直算要 8192² 约 6711 万次,这里是 21.3 万次,差 315 倍。致谢里他们感谢理查德·加温「在沟通与鼓励上的关键作用」。这一招不是他们最先想到的。高斯为从观测插值小行星的轨道写过一篇《用新方法处理的插值理论》,生前没有发表,1866 年收进全集第三卷第 265 页起,编者在卷末注里说它的初稿「似乎始于 1805 年 10 月」;今人考证(海德曼、约翰逊与伯勒斯 1984)指出,里面用的正是把长度拆成因子、分步求和的同一招。二十世纪又有龙格 1903 年的倍长格式、丹尼尔森与兰乔什 1942 年的办法;库利与图基自己在开头引的是耶茨的析因试验算法与古德 1958 年的一篇。
拖 m 看 N = 2 的 m 次方时两种算法差多少;按「下一级」看八个点的蝶形图一级一级地合
N = 1024 时照直算要 1,048,576 次乘加,按二拆只要 20,480 次,省下 51.2 倍;N 每翻一倍,这个倍数也差不多翻一倍。
