在研究自己的大整数实现时,我查看了Java的BigInteger源,以进一步了解乘法算法,并且主要关注multiplyToLen()
。
总体而言,该功能似乎具有通用的小学倍增算法方法,但我无法理解其中的关键部分。
首先,该算法经过第一个循环,其中x和y是要相乘的两个数字,而z是乘积:
int xstart = xlen - 1;
int ystart = ylen - 1;
...
for (int j=ystart, k=ystart+1+xstart; j >= 0; j--, k--) {
long product = (y[j] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry;
z[k] = (int)product;
carry = product >>> 32;
}
z[xstart] = (int)carry;
然后,它进入下一个循环,似乎更接近于等级算法。
for (int i = xstart-1; i >= 0; i--) {
carry = 0;
for (int j=ystart, k=ystart+1+i; j >= 0; j--, k--) {
long product = (y[j] & LONG_MASK) * (x[i] & LONG_MASK) +
(z[k] & LONG_MASK) + carry;
z[k] = (int)product;
carry = product >>> 32;
}
z[i] = (int)carry;
}
我尝试使用十进制数来跟踪两个循环都没有用,而且我无法掌握第一个循环与第二个循环的功能。
乘法运算的哪一部分在第一个循环中完成?
答案 0 :(得分:0)
第一个循环将两个整数相乘(分别来自每个BigInteger x
和y
),然后将结果的低32位存储在结果数组{{ 1}}。高32位用作进位z
和x
中下一个较高的整数对。
其他循环几乎相同,但是它们必须将结果添加到已经存储在y
数组中的整数中,因此它们不像第一个那样简单。
摆弄z
和long
的位仅用于将整数视为 unsigned 32位值(Java通常不知道unsigned整数),将其提升为64位整数,然后屏蔽低32位以获得无符号的32位值。 64位乘法结果无视第63位的任何溢出。低位存储(循环1 )或加( other循环)到先前循环的已计算结果中,在LONG_MASK
中找到。前32位用作下一次迭代的进位。
通常是这样完成的。我的BigIntegers的Delphi代码和IIRC一样,这也是Knuth在他的《计算机编程艺术》(第二卷)中显示的算法。