按位 - 比特计数的公式含义?



这里是Integer.bitCount(int i)的代码副本

我理解所有的运算符,但不明白那些神奇的数字是如何计算出来的!有人能向我解释一下吗?我可以看到模式(1,2,4,8,16&0x5,0x3,0x0f)。

        public static int bitCount(int i) {
            // HD, Figure 5-2
            i = i - ((i >>> 1) & 0x55555555);
            i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
            i = (i + (i >>> 4)) & 0x0f0f0f0f;
            i = i + (i >>> 8);
            i = i + (i >>> 16);
            return i & 0x3f;
        }

好吧,您的代码是针对32位整数的,但让我们来计算16位的第一步,因为字母表没有32个字母。假设输入的二进制形式(字节边界用空格表示)是

i                  = ABCDEFGH IJKLMNOP
i >>> 1            = 0ABCDEFG HIJKLMNO
(i >>> 1) & 0x5555 = 0A0C0E0G 0I0K0M0O

因此,第一次分配中右侧的前两个比特是(AB - 0A)。尝试组合:

A  B  AB-0A
0  0  00-00 = 00
1  0  10-01 = 01
0  1  01-00 = 01
1  1  11-01 = 10

因此,该结果的前两位会为您提供输入前两位中的位数计数。这同样适用于所有其他两个比特的组。

现在你又做同样的事了。这一次我们将考虑以4为基数的输入,因此两个比特形成下面符号的一个数字,我们可以使用完整的32比特。

i                      = ABCD EFGH IJKL MNOP
i & 0x33333333         = 0B0D 0F0H 0J0L 0N0P
i >>> 2                = 0ABC DEFG HIJK LMNO
(i >>> 2) & 0x33333333 = 0A0C 0E0G 0I0K 0M0O

因此,结果的前四位是(0A + 0B) = A + B,对于任何其他四位组也是如此。因此,在这一点上,每组四个比特都包含原始输入中这四个比特的比特计数。

使用底座16,下一步是

i                            = AB CD EF GH
i >>> 4                      = 0A BC DE FG
i + (i >>> 4)                = A(A+B) (B+C)(C+D) (D+E)(E+F) (F+G)(G+H)
(i + (i >>> 4)) & 0x0f0f0f0f = 0(A+B) 0(C+D) 0(E+F) 0(G+H)

这是因为每个四位组中的位计数总是小于四,所以添加两个这样的计数可以用四位表示而不会溢出。因此,加法不会有从一个四位16进制数字到另一个的任何溢出。此时,每个字节都包含该输入字节的位计数。其他算法可能会使用巧妙的乘法来继续,但你引用的代码在接下来的步骤中也坚持加法。

i                           = A B C D
i >>> 8                     = 0 A B C
i2 = i + (i >>> 8)          = A (A+B) (B+C) (C+D)
i2 >>> 16                   = 0 0 A (A+B)
i3 = i2 + (i2 >>> 1         = A (A+B) (A+B+C) (A+B+C+D)
i3 & 0x3f                   = 0 0 0 (A+B+C+D)

这再次利用了数字之间没有溢出的事实。

相关内容

  • 没有找到相关文章

最新更新