乘法算法

乘法算法是计算两个数值相乘乘积的算法。为了提高运算效率，不同大小的数字适用不同的乘法算法。自十进制数字系统诞生以来，就已开始发展乘法算法。
网格法.
将两个乘数分解（“划分”）为百位、十位或个位的部分，然后在相对简单的乘法步骤中直接算出这些部分的乘积，再将其一一相加以算出最终结果。用这种方法计算 formula_1，可以画出如下网格：
最后再通过一次求和或逐行累加得到结果（见右），实质是计算了 formula_2。
这种计算方法（尽管不一定显式地用网格排列乘数）也称为「部分乘积算法」。它的本质是分别计算简单的个位乘法，所有加法都留到最后的「加总」阶段。
尽管随着位数的增加，伴随的中间过程越来越繁琐，但网格方法原则上可以应用于任何大小的乘数。一般认为此方式是引入多位乘法概念时，有用的显式方法，而在当今利用计算器或电子表格就能完成大多数计算的时代，它可能是某些学生唯一需要的乘法算法。
长乘法.
位值制数字系统在人类社会的垄断性地位，使得长乘法成为最自然的乘法算法，世界各地的学校都会教学生使用这种算法完成日常的乘法计算。其内容是：将一个乘数乘以另一个乘数的每位数字，然后将所有数字按照适当的位置相加得出结果。这需要预先记住所有个位数字两两相乘后的结果，即华人世界常见的乘法表。长乘法又被称为教科书乘法或标准乘法。
若在十进制下，人工计算较大的数字加乘，长乘法是常见的算法。电脑在二进制下，也有类似的算法「移位和相加」，不少现代的处理器已设计最佳化的乘法线路，以进行快速的乘法计算，但其代价是硬体会变的更加复杂。若是在纸上计算长乘法，会先将所有数字写下，然后相加，若是使用珠算，会在计算完每一个乘积后，直接和已计算的和加总。
示例.
此例用长乘法计算23,958,233（被乘数）乘以5,830（乘数），结果是139,676,498,390（积）。
以下的虚拟码描述上述乘法的步骤。此作法会持续的更新乘积，在乘完所有数字后，乘积即为结果。其中+=运算子用来表示将某变数原有的值加上其他的值，再存回该变数中（类似在Java及C语言中的用法），以让程式紧凑。
<syntaxhighlight lang="pascal">
multiply(ab[1..q, base) // index 1对应数字的个位数
</syntaxhighlight>
优化空间复杂度.
假设在基数为formula_3，令 formula_4 为两个输入数字位数长度的总和，若其结果需保存在存储器中，则其空间复杂度通常为formula_5。然而在某些应用中，不需要把整个结果保存在内存中，而可以在计算时将数字以字元流的方式输出（例如输出到系统终端或文件中）。在这些情况下，长乘法的优势在于可以将其轻松表示为对数空间算法——也就是说，只需要一个工作空间与输入中位数的对数成正比的算法（formula_6），这是乘数之积的双重对数（formula_7）。注意，乘数本身仍保留在内存中，并且在此分析中忽略其 formula_5 的空间。
只要知道之前乘积产生的进位，就可以由最低位起，一位一位的计算乘积的每一位数字，这是优化空间复杂度的关键。令"a""i"和"b""i"分别是被乘数及乘数的第"i"位数字，"a"和 "b"的最高位都已补0，补到"n"位数，而"r""i"是乘积的第"i"位，而"c""i"是计算"r""i"后产生的进位（i=1表示是个位），则
or
简单的推论可以证明进位不会超过"n"，"r""i"的总和不会超过"D" * "n"：第一栏的进位是0，其他栏最多有"n"个数字，最多也只会从前一栏进位"n"。总和最多是"D" * "n"，进位到下一位的最多是"D" * "n" / "D"或"n"。因此这些数字都可以用O(log "n")位数储存。
伪代码下的对数空间演算法为<syntaxhighlight lang="pascal">：
multiply(ab[1..q, base) // Operands containing rightmost digits at index 1
</syntaxhighlight>
在计算机中的用法.
有些集成电路会实现乘法，可能是用硬件或是微程序，可能针对各种整数及浮点数。在高精度计算中，在乘比较小的数字时，用底数为2"w"的长乘法，其中"w"为字元的位元数。
若要用此方式乘二个"n"位数数字，约需要"n"2次的运算。若用比较型式的方式表示，用数字位数这个自然的数字大小度量，用长乘法乘二个"n"位数数字的时间复杂度是Θ("n"2)。
若要用软体实现，长乘法演算法需要处理在加法时会出现的溢位问题，可能会很耗成本。典型的作法是用比较小的基底来进行运算，例如"b"，而让8"b"为机器中表示的整数大小。这样可以进行几次运算之后才会溢位。若数字太大，可以只加数字的一部份到结果中，或是进位，将剩下的数字映射为一个小于"b"的较小数字。此作法称为「正规化」。Richard Brent有在其Fortran软体包MP中使用此一作法。
格子乘法.
格子乘法在演算法上和长乘法等效。需要在纸上划格子，以引导计算，并且将乘法和加法分为二个步骤进行。这是在1202年在斐波那契的《》中引进到欧洲。斐波那契用此方式心算，用左手和右手处理计算的中间值。16世纪的在《Umdet-ul Hisab》书籍上列出了此演算法六种不同的变体。在奥斯曼帝国的恩德伦学校中，广为使用此一演算法。纳皮尔的骨头（Napier's bones）或称为纳皮尔算筹（Napier's rods）也是用此方式，是约翰·纳皮尔过世的1617年发表。
如图所示，被乘数和乘数写在格子的上方和右边，此方法在花拉子米的《算数》（Arithmetic）书中有提到，这是斐波那契的来源之一，曾被Sigler在2002年的《Fibonacci's Liber Abaci》中提到。
示例.
考虑以下较复杂的计算，考虑23,958,233乘以5,830，结果是139,676,498,390。不过以下计算中，其中的23,958,233是写在格子的上方，5,830写在右方。将乘积写在格子的二个三角形中，将和写在左边和下方。结果条列如下：
二进制或农夫演算法.
是广为在农民中使用的算法，其中不需要像长乘法一样记忆乘法表。此演算法曾在古埃及使用，农夫演算法的优点是可以快速教授、不需要记忆、若没有纸笔的话，也可以用其他东西辅助计算（例如筹码），缺点是步骤比长除法要长，在计算大数字的乘法时不方便，
说明.
在纸上，写下被乘数，被乘数的下方写下被乘数反复除二（且无条件舍去小数）的结果，被乘数的旁边写下乘数，乘数下方写上乘数反复乘二的结果。一直到被乘数那一栏为1为止。将乘数那一栏的数字相加，但若被乘数那一栏为偶数，跳过此数字不累加，所得结果即为乘积。
示例.
以下用农夫演算法计算11乘以3 。
说明上述的步骤：
此作法有效的原因是因为乘法满足分配律，因此：
以下是一个复杂的例子，仍用之前用过的范例（23,958,233 and 5,830）：
电脑中的二进制乘法.
这是农夫演算法的变体。
二进制下，长乘法会变成很简单的处理，针对每一个被乘数位数的1，将乘数往左位移适当的位元数，将乘数各次位移的结果相加，即为乘积。在一些中央处理器中，加法和位移的速度会比乘法要快，尤其被乘数不大，或是几乎是定值的情形。
移位和相加.
以往的电脑会用「移位和相加」的乘法来计算小整数的乘法。二进制的长乘法和农夫演算法都可以简化到相同的演算法。
在二进制下，将数字和二进制的一个位元相乘，可以简化为各位元的逻辑与运算。会将算出来的部份和相加。，大部份目前的微处理器都会以此方式或是其他类似方式（例如布斯乘法算法）实现不同整数以及浮点长度的乘法，，可能是用乘法器中或是微程序。
目前的处理器，位元的移位运算会比乘法要快很多，因此可以用往左移位代替乘以2的次幂。乘以常数的乘法也可以用一连串的移位和加减法来代替。例如，以下是只有移位及相加来表示乘以10的演算法。
有时的移位和加减法的组合会比硬体乘法器还快。
若电脑没有乘法的运算，需要用上述方式来进行计算，若将向左移位表示为相同的数加二次（两者在逻辑上等价），也可以延伸到浮点数。
平方的四分之一乘法.
可以用平方的算式，计算二个数的乘积，有些来源的算式中会包括取整函数，此方式源自于巴比伦数学（西元前2000-1600年）。
和为整数，若和中有一个为奇数，另一个也一定会是奇数，因此上式中若有一项在取整数之前有分数，另一项也会有，两者会相消，不会影响所得的结果。以下是从0到18计算平方的四分之一取整数的对照表，可以计算以内的乘法：
若要计算9乘3，其和以及差分别是12以及6，根据上式可得36和9，两者的差是27，这就是9乘3的乘积。
Antoine Voisin在1817年有出版一个平方的四分之一的表，从1列到1000，可以帮助乘法的运算。Samuel Laundy在1856年有出版过1到100000的表，Joseph Blater在1888年出版了1到200000的表。
平方的四分之一乘法曾用在模拟计算机上，以形成二讯号相乘的模拟信号。二个输入电压的和或差可以用运算放大器达到。电压平方可以用电路达成。最后二个平方的四分之一以及两电压的差以及再用运算放大器实现。
Everett L. Johnson在1980年时提出将此方式应用在数码乘法器中。为了产生8位元整数的乘积，数位装置计算两数的和以及差，查表计算平方，计算差值，再往右移位二个位元。
平方的四分之一乘法对8位元的系统有益，可以在没有硬体乘法器的情形下实现乘法。Charles Putney有将此演算法实现在MOS 6502中。
复数乘法演算法.
复数乘法包括四个实数乘法以及二个加法。
或
不过有办法将实数乘法由四个减少到三个
乘积("a" + "bi") · ("c" + "di")可以用以下方式计算。
此演算法只用了三个乘法，比原来的四个乘法少一个，但加减法由原来的二个增加到五个。假如乘法的成本远大于计算加减法的成本，此演算法的速度会比原来的演算法快。在现代先进的电脑上，乘法和加法花的时间可能相同，那么此演算法就没有速度上的优势。若使用浮点数计算，此演算法可能会有精准度下降的问题，因此需要取舍。
在FFT（或是其他的线性映射），若是乘以固定系数（"c" + "di"，在FFT中称为旋转因子）的复数乘法，其中二个加法（"d"−"c"和"c"+"d"）可以事先计算，需要即时计算只剩三个乘法以及三个加法。不过若是配合有浮点运算器的处理器，加法的速度和乘法相当，因此减少乘法，增加加减法的演算法，没有速度上的优势。
大数字的快速乘法演算法.
Karatsuba乘法.
若需要计算到上千位数字相乘的系统，例如计算机代数系统或高精度计算函式库，长乘法的速度太慢。因此会使用Karatsuba算法，此乘法演算法是在1960年发现的，在1962年出版。此乘法演算法的精神在于观察到二位数的乘法可以不用传统四个乘法的作法，可以只用三个乘法完成。这是分治法的例子。假设要将二个二位数"m"进位数字 "x"1" m + x"2和"y"1" m + y"2相乘：
若要计算三个"m"进位数字的乘积，又可以用上述的技巧，使用递归的方式进行（但需要改为其他的进位），此方式。只要计算出乘积数字，再将数字相加，需要"n"个步骤。
Karatsuba算法的时间复杂度是O("n"log23) ≈ O("n"1.585)，此方式明显的比长乘法要快。因为递归产生的额外计算，若"n"较小时，Karatsuba算法会比长乘法慢，因此在"n"较小时，会切换回长乘法进行计算。
Karatsuba算法是第一个时间复杂度渐进的比长乘法快的演算法，也可以视为是快速乘法理论的基础。
1963年时，Peter Ungar建议将"m"改为"i"，以产生快速复数乘法的演算法。若要计算 ("a" + "b i") · ("c" + "d i")，可依以下步骤进行：
如同上述复数乘法演算法所述的一样，需要三个乘法以及五个加减法。
Toom-Cook 算法.
另一种乘法的演算法是Toom-Cook算法，或称为Toom-3算法。Toom-Cook算法将每一个要相乘的数字切成几部份，是Karatsuba算法的推广。三路的Toom-Cook演算法可以针对大小为formula_15的被乘数和乘数进行乘法，其成本是大小为formula_16的被乘数和乘数乘法的5倍，因为运算加速的系数是formula_17，Karatsuba算法的加速系数是formula_18。
若用递回的方式将数字分成更多份，可以再缩减计算时间，但位数管理以及加法的成本也会增加。若位数到上千位数，一般会使用傅立叶转换，速度多半会比较快，若位数更多，傅立叶转换的优势更加明显。
傅立叶变换法.
Strassen（1968年）曾提出用快速多项式乘法来计算快速整数乘法的基本概念。后来在1971年由Strassen和找到理论和实务的确认，所得的就是Schönhage-Strassen演算法。
下限.
若用单一处理器将二个"n"进位的数字相乘，时间复杂度有一个trivial的下界Ω("n") ，没有更接近实际应用的下界。乘法在以外（"p"为任意整数），意思是不存在固定深度，多项式（甚至是次指数）大小，以AND、OR、NOT、MOD"p"电路组合成的电路可以计算乘法。"q" to multiplication.-->。
多项式乘法.
上述的乘法演算法也可以用来计算多项式的乘法。例如Strassen演算法就可以用来计算多项式的乘积。而
也可以将多项式的乘法转换为二个整数的乘法。
以下是用长乘法来计算多项式乘法的例子：