字节数组上的Karatsuba乘法优化

时间:2015-05-04 07:52:22

标签: java arrays algorithm optimization

我已经实现了两个字节数组的乘法,它工作正常。更确切地说,我需要将64字节操作数与32字节操作数相乘。

我以最简单的方式实现它:我进行双循环,并为每个数组中的每个字节计算产品。 因此,对于特定值,需要64 * 32 = 2048步。

我尝试使用Karatsuba方法对其进行优化。 所以我按照以下方式进行:

a的长度为64个字节,b的长度为32个字节。

我们将a分成:a = p * 16^(32) + q(所以pq的长度均为32字节)和计算:a * b = p * b * 16^(32) + q * b(产品是计算的)我之前描述的功能。)

我得到了正确的结果,但计算需要相同的时间:2个32字节数组的2次乘法:32 * 32 * 2 = 64 * 32 = 2048

我的问题如下:使用Karatsuba优化我的乘法,我应该完全递归编程吗?以其他方式它永远不会更快?

提前谢谢你:)

2 个答案:

答案 0 :(得分:3)

哇!我作为程序员的第一份工作之一是优化COBOL运行时系统的乘法算法 - 这是31年前的事。

我认为你会发现有效的技术是将字节组合成更大的单位。当时只有32位可用,因此两个字节合并为一个短路,短路相乘以得到一个32位的int。但是在Java中你有64位可用,所以你可以乘以两个整数来获得一个长的。

因此,你应该通过添加字节来创建一个16个整数的数组 a1 和一个数组 b1 8个整数。例如。有时这样:

a1[0] = (a[0] << 24) + (a[1] << 16) + (a[2] << 8) + a[3]

或者你可以写一个循环来更简洁地做到这一点。

然后乘以a1和b1,这应该进行128次操作。

我会担心溢出和已签名与无符号值。最高位后面的数字应该是无符号的,但Java没有无符号修饰符。但是,在Java 8中,对未签名操作有一些支持:请参阅Primitive Data Types

如果无法使用ints / long进行无符号处理,则可以将2或3个字节的组合组合成int并浪费一些顶部位,为符号位提供空间。

答案 1 :(得分:2)

是的,Karatsuba算法只有在递归的情况下才有效。但请记住:Karatsuba 并不总是比更快,需要O(n^2)(通常我们假设两个数字具有相同的长度,如果我们要增加大数字)。对于小输入(可以是1,它可以是15,取决于你的CPU),简单的算法可以更快,因此Karatsuba的最佳使用是:

  1. if size > MIN_SIZE_FOR_KARATSUBA(你必须通过实验找到它),然后进行拆分并递归调用Karatsuba。
  2. 如果size <= MIN_SIZE_FOR_KARATSUBA,则只需将它们与简单算法相乘。
  3. 另外,不要在乘法中将数组拆分为字节,将它们存储在 base 1000 中的整数或类似的内容中,因为您可以轻松地溢出类型。

    描述了Karatsuba算法的最佳实现in this link。通常Karatsuba会占用O(n log n)内存,但这里有一些技巧只需要O(n)内存。

    如果您不想多次使用函数调用(因为函数调用是编程中最慢的操作),那么您可以自己使用循环并实现堆栈,如my implementation中所示。