图姆-库克算法

图姆-库克算法（），有时也被称为Toom-3算法，由安德鲁·图姆命名，他提出了这种算法的基本原理，而斯蒂芬·库克则最先用简洁的形式描述并改进了这种算法，将其作为大整数的乘法算法。
图姆-库克算法的原理是：对于给定的两个大整数formula_1和formula_2 ，将formula_1和formula_2分成formula_5个较小的部分，每个部分的长度为formula_6 ，并对这些部分执行运算。随着formula_5的增长，可以组合许多乘法子运算，从而降低算法的整体复杂度，然后再次使用图姆-库克算法递归计算乘法子运算，依此类推。Toom-3和图姆-库克两个术语有时会被错误的混用，但事实上Toom-3只是图姆-库克算法在formula_8时的特例。
Toom-3将9次乘法降低至仅需5次，使其在formula_9的时间里运行。通常，Toom-formula_5的时间复杂度为formula_11 ，其中formula_12。formula_13是在乘法子运算上花费的时间，formula_14则是花费在对小常数进行的加法和乘法运算上的时间。著名的Karatsuba算法实际上是图姆-库克算法的特例，在Karatsuba算法中，原始乘数被拆分成两个较小的数，而原本的4次乘法运算缩减为3次，使之在formula_15的时间内完成运算。Toom-1等价于普通的长乘法，具有formula_16的复杂度。
尽管可以通过增加formula_5来使指数formula_18任意接近1，但函数formula_14增长速度非常快。混合级别图姆-库克算法的增长率直到2005年仍然是一个广为研究的开放性问题。根据高德纳所描述算法的一种实现，其复杂度可降低至formula_20。
由于工作时的开销，当乘数包括较小的数时，图姆-库克算法会比长乘法更慢，因此它适用于中等规模的乘法。对于更大规模的数据，则有渐进更快的史恩哈格·施特拉森算法（复杂度为formula_21）。
这一算法由安德鲁·图姆1963年首次描述，并在斯蒂芬·库克1966年的博士学位论文中得到渐进等效的改进。
细节.
本节将讨论对于任意给定 formula_5 值， Toom-formula_5究竟是如何运作的，这是马可·波德拉托对图姆-库克多项式乘法的简化描述。这个算法包括五个主要步骤：
在典型的大整数实现中，每个整数都表示为formula_2进制的数字序列（formula_2通常取较大的数）。在此示例中，formula_26，因此每个数字序列对应一组十进制数字（在实践中，formula_2通常取formula_28的幂）。设要相乘的两个大整数formula_29 、 formula_30分别是：
这对乘数实际上比图姆-库克算法通常要处理的数据小很多，在此使用学校里学习的普通乘法可能会更快，但这个示例仍有助于说明图姆-库克算法的工作原理。
拆分.
第一步是选择基数formula_31，使得两个数字formula_29和formula_30可以分成formula_5段大小不超过formula_35的数字（例如在Toom-3算法中，拆分段数应至多为3）。formula_36常常根据如下公式求得：
我们的示例将演绎Toom-3算法的运算过程，因此确定formula_38，接着把formula_29和formula_30拆分为3段，即formula_41和formula_42，则有：
然后，我们把这些数作为formula_44阶多项式formula_45和formula_46的系数，with the property that formula_47 and formula_48：
定义这些多项式的目的在于：如果计算出它们的乘积formula_51，我们的答案就会是formula_52。
如果乘数位数不同，对于formula_29、formula_30分别取不同的formula_5值十分有用，我们将其称为formula_56和formula_57。例如，算法“Toom-2.5”是指formula_58且formula_59时的图姆-库克算法。这时formula_31中的formula_36通常被确定为：
求值.
图姆-库克算法包含一种常用的方法，来计算多项式formula_63、formula_64的乘积。注意，次数为formula_65的多项式可以通过formula_66个空间中的点确定（例如一次多项式是一条直线，它由两个点确定）。这个方法是在各个点上求值formula_67和formula_68，然后把这些点相乘以获得多项式乘积上的点，最后进行插值以找到其系数。
由于formula_69，我们将需要formula_70个点来确定最终结果formula_65。在Toom-3的情况下，formula_72。无论选择什么点，该算法都可以工作（有一些小例外，请参阅插值中的矩阵可逆性约束），但为了简化算法，最好选择较小的整数值，例如formula_73 、formula_74 、formula_75和formula_76。
无穷大是一个常被使用的不寻常点，其记作formula_77或formula_78。求多项式formula_45在无穷大时的值，实际上意味着令formula_80的上限为formula_81 且趋向无穷大。因此，formula_82总是其高阶系数的值（formula_83是上文中的系数）。
在我们的Toom-3示例中，我们将使用点formula_73 、 formula_74 、 formula_75 、 formula_76和formula_77，这些选择简化了求值，如下式子：
对于formula_46也是如此。在示例中，我们得到的值是：
如上所示，这些值可以包括负值。
为了下文的阐述，把这个求值过程视作矩阵向量乘法较为有用。其中，矩阵的每一行都包含求值点之一的幂，且向量包含多项式的系数：
The dimensions of the matrix are  formula_65 by  formula_56 for  formula_45 and  formula_65 by  formula_57 for  formula_46。除最后一列的 formula_74 以外，无穷大的行总是formula_73。
更快的求值.
与上述公式相比，多点求值可能会减少基本运算（加、减）的次数，更快获得需要的结果。波德拉托 为Toom-3给出的序列如下所示，它是在运行示例的第一个操作数（多项式formula_45上进行的）：
此序列需要进行五次加/减运算，比简单求值少一次，同时节省了在计算formula_101时乘以formula_102的开销。
点乘.
与对多项式formula_67和formula_68所进行的乘法不同，将formula_105 和formula_106被求出的值相乘仅涉及整数相乘——这是原始问题的较小实例。我们递归调用我们的乘法过程来使每对已求值的点相乘。在实践中，随着乘数减小，算法将逐渐过渡为教科书长乘法。令formula_107为多项式乘积，我们将得到：
如上所示，这些值也可以是负数。对于足够大的数值，这里是最昂贵的、唯一与formula_29、formula_30大小不成线性关系的步骤。
插值.
这一步最为复杂。与求值相反：给定多项式乘积formula_110上的formula_65点，我们需要确定其系数。换句话说，我们要在右侧求解其向量的矩阵方程：
此矩阵的构造与求值步骤中的矩阵相同，不过它是formula_113的。我们可以用高斯消元法来求出方程的解，但这样非常昂贵。根据以下事实：只要求值点的选择合适，这个矩阵就是可逆的。因此我们有：
接下来即要求得该矩阵的向量积。尽管矩阵中包含分数，但所得的系数却是整数——因此所有这些都可以在整数算术中完成，仅仅是与小常数进行加减乘除。图姆-库克设计时面临的一个困难挑战就是找到有效的操作顺序来计算该乘积。下面是波德拉托为Toom-3找到的一组顺序，通过上面的示例演示：
现在我们知道多项式乘积formula_107：
如果我们使用不同的formula_56、formula_57或求值点，矩阵和我们的插值将改变。但是它不依赖于输入，因此可以对任何给定的参数集进行硬编码。
重组.
最后，我们将求出formula_119的值以获得最终结果。很显然，由于formula_35是formula_2的幂，因此对formula_35的幂的乘法同样也可以应用于所有以formula_2为底数的数值。在这个示例中，formula_124且formula_38。
这实际上是formula_126与formula_127的乘积。
formula_5在其他取值时的插值矩阵.
这里我们给出了几种formula_56和formula_57取常见较小值的插值矩阵。
Toom-1.
Toom-1（formula_131）需要一个求值点，这里选择formula_73。它退化为长乘法，并且使用恒等矩阵的插值矩阵。
Toom-1.5.
Toom-1.5（formula_134）需要两个求值点，这里选择formula_73和formula_77，且其插值矩阵就是恒等矩阵。
这里亦退化为长乘法：一个因数的两个系数都乘以另一个因数的两个系数。
Toom-2.
Toom-2（formula_138）需要三个求值点，这里选择formula_73、formula_74和formula_77。它与 Karatsuba 算法相同，其插值矩阵为：
Toom-2.5.
Toom-2.5（formula_143）需要四个求值点，这里选择formula_73、formula_74、formula_75和formula_77。它的插值矩阵为：