我们以255为例。随着我们的进行,这些位被组合在一起。首先我们从 255 开始0b1111.1111
(二进制中的 8 个 1)
第一行代码是:
i = i - ((i > > > 1) & 0x5555555555555555L);
这条线正在梳理每一对 1。由于我们有 8 个 1,我们希望将我们的对组合起来,得到类似 2,2,2,2 的东西。因为它是二进制的,所以我们期望 10101010。
让我们看看i > > > 1
。我是0b1111.1111
,这是向下移动 1,所以我们得到0b0111.1111
. 我们取交集,&
,0b0101.0101
(这是从 5 到 101 的二进制)。这样做会保留我们一半的位,特别是所有最初处于偶数位置的位(从我们的初始数字开始的第 2、4、6、8 位)。
然后我们从我们的初始值中减去这个,这有点hacky。我们正在尝试将我们的最高位添加到我们的最低位,所以我们可以这样做:
((i > > > 1) & 0x5555) + (i & 0x5555)
左边的项是最高位,右边的项是最低位。但我们知道 i = 2*(top bits) + 1*(bottom bits),因为 top bits 上移了 1(这与乘以 2 相同)。因此,通过将最高位减去 1 次,我们得到了相同的结果。
好的,现在我们准备好了第二行代码。我们目前有0b1010.1010
for i,我们准备添加每对 2。我们希望得到 4,4(每半使用 4 位)或0100.0100
二进制。代码是:
i = (i & 0x3333333333333333L) + ((i > > > 2) & 0x3333333333333333L);
我们得到每组 4 个中的前 2 个数字和后 2 个数字,我们正在添加它们。0x3333 = 0b0011.0011.0011.0011
所以我们可以看到,将&
, 与 3 的交集保留在一组中的底部 2 个数字。我们首先得到底部的两个数字,然后我们将 i 移动 2 个位置以获得顶部的 2 个数字。然后我们添加:0010.0010 + 0010.0010 = 0100.0100
. 完全符合预期。
接下来我们将 2 组 4 加在一起。
i = (i + (i > > > 4)) & 0x0f0f0f0f0f0f0f0fL;
0x0f0f = 0b0000111100001111
,因此,如果我们与此相交,我们将保留每 4 个数字。我们将 i 添加到自身降档 4,因此我们计算0100.0100 + 0000.0100 = 0100.1000
。4 + 4 应该返回 8, and 8 = 0b1000
,但仍然需要删除顶部的“4”。与的交集就是这样做的0f0f0f0f
。
所以现在我们有了0b1000
,也就是 8。其余的步骤添加了更高的位(比如 2 组 8 在一起,而不是 2 组 16 ..)但是由于我们的数字(255)只有 8 位长,所以更高的位都是 0,所以这不会影响我们的结果。