整数乘法

利用分治、递归的思想,对传统的整数乘法进行分解。同时介绍Karatsuba,其是如何减少基本的乘法运算次数。

一、小学乘法

  例如x=5678、y=1234,这两个整数相乘,相当于对x的每一位循环,循环体内则是将x的当前位与y相乘,必要时产生进位,得到的结果根据该位在x中的位置左移相应位数(相当于末尾添0),将所得的全部结果相加即最终结果。每个循环执行4次乘法和不超过4次的加法,因此循环体内执行基本操作次数设为2n(n即数位数),则一共n次循环和循环结束后若干次加法,因此执行操作次数约为2n2。利用大O表示法,时间复杂度应为O(n2)。

二、RecIntMult算法

  同样对于两个n位的整数x、y。可以使用另一种表示形式:

x = 10(n / 2) * a + b
y = 10(n / 2) * c + d
x * y = (10(n / 2) * a + b) * (10(n / 2) * c + d)
   = 10(n) * (a * c) + 10(n / 2) * (a * d + b * c) + b * d

  其中a、c相当于x、y的前n / 2 位,而b、d就是x、y的后n/ 2 位(假设n为偶数)。因此就将x * y 转为a * c、a* d 、 b * c、b * d四个乘法运算和若干加法运算(这里的乘10(n)相当于第一部分的末尾添0)。而对于分解后的四个乘法运算,若它们的位数大于1,则可以继续分解,而当分解到1位时,就可以执行简单的个位乘法运算。

  假设x、y均为四位整数,我们用函数表示其执行乘法的次数,则f(4) = 4 * f(2)、f(2) = 4 * f(1)、f(1) = 1,则f(4) = 16。不难发现,n位整数乘法运算次数等于n / 2 位整数乘法运算次数的4倍,往下递归,直至n = 1,此时乘法运算次数为1。即n一直除2,直至结果等于1,那么n被除了几次2就有几个4相乘,则用数学公式表示为f(n) = 4(log2n)。用大O表示法,时间复杂度为O(4(log2n)) = O(n(log24)) = O(n2),因此这种方式的分治算法只是将第一种方法分解成许多的小整数乘法,并没有减少乘法运算次数。

三、Karatsuba算法

  RecIntMult算法虽然将大整数x、y各转为2部分的小整数进行运算,但是每一部分都会和另一个数的全部部分相乘,因此最后x的每一位数都会和y的每一位数相乘,所以实际的乘法运算次数肯定是n2
  而Karatsuba算法的思路如下:

(a + b) * (c + d) - a * c - b * d = a * d + b * c
 x * y = 10(n) * (a * c) + 10(n / 2) * (a * d + b * c) + b * d
    = 10(n) * (a * c) + 10(n / 2) * ((a + b) * (c + d) - a * c - b * d) + b * d

  Karatsuba式子可能变的更长,但是x、y的乘法实际被分解为a * c、(a + b) * (c + d)、b * d三个乘法运算。第一步虽然将a * d + b * c转为了三个乘法运算,但是后两个乘法运算利用已经计算的结果,所以实际计算a * d + b * c只需要一次乘法运算。这也是Karatsuba减少乘法运算次数的关键。

  那么Karatsuba对于n位整数,执行乘法次数为f(n) = 3 * f(n / 2),因此时间复杂度实际为O(3(log2n)) = O(n(log23)) = O(n1.59)

  Karatsuba算法使用递归实现比较消耗性能,当整数位数较小时,使用基本的乘法反而效率更高。

posted @ 2019-09-28 15:02  Idempotent  阅读(64)  评论(0)    收藏  举报