有人能帮忙解释一下n&-n
是什么意思吗?以及它的意义是什么。
这是一种老技巧,它可以给出一个只有一个位的数字,即在n
中设置的最后一位。至少在补码算术中,这种方法几乎是通用的。
其原理:一个数的负数是通过对该数进行反转,然后加1来产生的(这就是补码的定义)。当你加1时,从底部开始设置的每个位都会溢出到下一个更高的位;一旦到达零位,这个过程就停止了。这些溢出的位将全部为零,上面没有受影响的位将互为反码,因此留下的唯一位是停止级联的位——最初为1并被反转为0的那个位。
P.S. 如果你担心在线性补码中运行,这里有一个适用于两种方式的版本:
n & (~n + 1)
for (;j=n&(-n);n^=j)
- Aki Suihkonen在大多数人关心的系统上,它将为您提供n可被整除的最高2的幂。
N&(-N)
会给你在N
的二进制形式中第一个位'1'
的位置。
例如:
N = 144 (0b10010000) => N&(-N) = 0b10000
N = 7 (0b00000111) => N&(-N) = 0b1
这个技巧的一个应用是将整数转换为2的幂次方之和。例如:
To convert 22 = 16 + 4 + 2 = 2^4 + 2^2 + 2^1
22&(-22) = 2, 22 - 2 = 20
20&(-20) = 4, 20 - 4 = 16
16&(-16) = 16, 16 - 16 = 0
我相信这是一种检测 n 是否为 2 的幂的技巧。当且仅当 n 是 2 的幂 (1, 2, 4, 8) 时,(n == (n & -n)) 成立。
(n&(n-1))==0
更简单。 - Jyothrilinga K我会在Mark Randsom精彩的阐述中添加一个自我解释的例子。
010010000 | +144 ~
----------|-------
101101111 | -145 +
1 |
----------|-------
101110000 | -144
101110000 | -144 &
010010000 | +144
----------|-------
000010000 | 16`
因为对于 x
从0到32,x & -x = {0, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 16, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 32}
。它被用于一些应用程序中的for循环跳转。这些应用程序可以用来存储累积记录。
for(;x < N;x += x&-x) {
// do something here
++tr[x];
}
正如@aestrivex所提到的,这是一种写1的方式。我也遇到过这种情况。
for (int y = x; y > 0; y -= y & -y)
这只是意味着 y=y-1,因为
7&(-7) 是 x00000111 & x11111001 = x00000001 = 1
n
的值和负数的表示方式(即1的补码与2的补码),它可能会导致未定义的行为或仅产生未指定和/或实现定义的值。我相信这是您不想使用/遇到的东西。 - user529758