公式 x & (x - 1) 是如何工作的?

How does the formula x & (x - 1) works?

来自 Hacker's Delight:第 2 版


这里的公式在这里似乎有点别扭。当x小于1? (如:(如示例中给出)0x0101 1000 - 0x0000 0000 对我来说没有任何意义)前者比第一个和单词也不存储带符号的向量。这是与此处特定的 RISC 相关的东西还是什么?


如本书注释部分所述。粗体字母对应单词的向量,如 x = 00000000。粗体字母不同于浅色面 1。如粗体 1 = 11111111,其中是一个 8 位字。


Edit2: 特别感谢 Paul Hankin 找出这里使用的非常规符号。粗体字表示 32 位大小的字,即 [00000001],浅色 1 表示 C 中的数字 1。

让我们来看看 x-1 做了什么。 假设 x 是一个值 '???? 1000 (?是 0 或 1)
=> x-1 = ???? 0111
=> x & (x-1) = ???? 0000

不管最右边的1放在x的哪个位置都非常相似。


要求的例子:
x=00001111
=> x-1=00001110
=> x & (x-1) = 00001110

P.s。 x-1 = 00001110 - 00000001 (<=> 00001110 + 11111111)

减 1

由于我们对十进制比对二进制更熟悉,因此有时查看十进制的情况会有所帮助。

十进制减1会怎样?以 1786000 - 1 = 1785999.

为例

如果用十进制的正数 x 减去 1

  • x右边的所有零变为9;
  • x最右边的非零数字减1;
  • 其他数字不受影响。

现在,在二进制中,它的工作原理完全相同,除了我们只有 0 1 而不是 0 123456789

如果用二进制数 x 减去 1

  • x右边的所有零变为1;
  • x最右边的非零位变为0
  • 其他位不受影响。

负数呢?令人高兴的是,使用 2 的补码表示负数的行为与正数完全相同。事实上,当查看 x 的位时,您可以从 x 中减去 1 而无需知道 x 是 signed int 还是 unsigned int。

x & (x-1)

让我们从一个例子开始:x = 01011000。我们可以按照我刚才解释的方式减去 1:

x   = 01011000
x-1 = 01010111

现在 bitwise-and 操作的结果是什么 x & (x-1)?我们取每一列中的两位;如果它们都是 1,我们写 1;如果其中至少有一个是0,我们写0。

x       = 01011000
x-1     = 01010111
x&(x-1) = 01010000

发生了什么事?

  • x右边的所有零保持为零;
  • 由于x-1;
  • x最右边的1变为0
  • 所有其他位不受影响,因为它们在 xx-1 中相同。

结论:我们已将 x 中最右边的 1 归零,而其他所有位不受影响。