让我们从乘法代码开始。这个想法实际上非常聪明。假设您以二进制形式写入 n1 和 n2。然后,您可以将 n1 视为 2 的幂之和:n2 = c30 230 + c29 229 + ... + c1 21 + c0 20,其中每个 ci 为 0 或 1。然后你可以把乘积 n1 n2 想象成
n1 n2 =
n1 (c30 230 + c29 229 + ... + c1 21 + c0 20) =
n1 c30 230 + n1 c29 229 + ... + n1 c1 21 + n1 c0 20
这有点密集,但这个想法是,两个数字的乘积是由第一个数字乘以构成第二个数字的两个的幂给出的,乘以第二个数字的二进制数字的值。
现在的问题是,我们是否可以在不进行任何实际乘法的情况下计算此总和的项。为了做到这一点,我们需要能够读取n2的二进制数字。幸运的是,我们可以使用班次来做到这一点。特别是,假设我们从n2开始,然后只看最后一点。这是 c0。如果我们然后将值向下移动一个位置,则最后一位是c0,依此类推。更一般地说,在将n2的值向下移动i个位置后,最低位将是ci。要读取最后一位,我们可以按位读取数字为1的值。这具有一个二进制表示形式,除最后一个数字外,其他位置均为零。由于 0 和 n = 0 表示任何 n,这将清除所有最上面的位。此外,由于 0 和 1 = 0 和 1 和 1 = 1,此操作将保留数字的最后一位。
好的 - 我们现在知道我们可以读取ci的值;那又怎样?好吧,好消息是,我们也可以以类似的方式计算序列n1 2i的值。特别是,考虑值 n1 << 0、n1 << 1 等的序列。每当你做左位移时,它相当于乘以2的幂。这意味着我们现在拥有计算上述总和所需的所有组件。这是您的原始源代码,并附上了正在发生的事情:
public static void bitwiseMultiply(int n1, int n2) {
/* This value will hold n1 * 2^i for varying values of i. It will
* start off holding n1 * 2^0 = n1, and after each iteration will
* be updated to hold the next term in the sequence.
*/
int a = n1;
/* This value will be used to read the individual bits out of n2.
* We'll use the shifting trick to read the bits and will maintain
* the invariant that after i iterations, b is equal to n2 >> i.
*/
int b = n2;
/* This value will hold the sum of the terms so far. */
int result = 0;
/* Continuously loop over more and more bits of n2 until we've
* consumed the last of them. Since after i iterations of the
* loop b = n2 >> i, this only reaches zero once we've used up
* all the bits of the original value of n2.
*/
while (b != 0)
{
/* Using the bitwise AND trick, determine whether the ith
* bit of b is a zero or one. If it's a zero, then the
* current term in our sum is zero and we don't do anything.
* Otherwise, then we should add n1 * 2^i.
*/
if ((b & 1) != 0)
{
/* Recall that a = n1 * 2^i at this point, so we're adding
* in the next term in the sum.
*/
result = result + a;
}
/* To maintain that a = n1 * 2^i after i iterations, scale it
* by a factor of two by left shifting one position.
*/
a <<= 1;
/* To maintain that b = n2 >> i after i iterations, shift it
* one spot over.
*/
b >>>= 1;
}
System.out.println(result);
}
希望这有帮助!