公式x&x-1如何工作?

问题描述

摘自 Hacker's Delight:2nd Edition

Formula to turn off the rightmost 1-bit of a word.


这里的公式似乎有点尴尬。当 x 小于时,如何从 1 向量(大概为 0x1111 1111 )中减去某些 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为例。

如果从十进制正数1中减去x

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

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

如果从二进制数1中减去x,则

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

负数呢?令人高兴的是,使用2的补码表示负数的行为就像正数。实际上,当查看x的位时,可以从1中减去x,而无需知道x是有符号整数还是无符号整数。>

x & (x-1)

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

x   = 01011000
x-1 = 01010111

现在按位和操作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置零,而所有其他位均不受影响。