C++ 我+=(i&;i)你认为呢?它是便携式的吗?
设C++ 我+=(i&;i)你认为呢?它是便携式的吗?,c++,integer,bit-manipulation,C++,Integer,Bit Manipulation,设i为有符号整数类型。考虑 i += (i&-i); i -= (i&-i); 其中最初i>0 这些是干什么用的?是否有仅使用算术的等效代码 这是否取决于负整数的特定位表示 来源:在线编码拼图的setter代码(无任何解释/注释)。i&-i是获取整数i最低有效位(LSB)的最简单方法 您可以阅读更多内容。 A1:你可以阅读更多关于“数学等价物”的内容。 A2:如果负整数表示不是通常的标准形式(即奇怪的大整数),则i&-i可能不是LSB。表达式i&-i基于用于表示负整数。简单地说
i
为有符号整数类型。考虑
i += (i&-i);
i -= (i&-i);
其中最初i>0
来源:在线编码拼图的setter代码(无任何解释/注释)。
i&-i
是获取整数i
最低有效位(LSB)的最简单方法您可以阅读更多内容。
A1:你可以阅读更多关于“数学等价物”的内容。
A2:如果负整数表示不是通常的标准形式(即奇怪的大整数),则
i&-i
可能不是LSB。表达式i&-i
基于用于表示负整数。简单地说,它返回一个值k
,其中除i
的最低有效非零位之外的每一位都设置为0
,但该特定位保持其自身的值。(即1
)
只要您提供的表达式在用于表示负整数的系统中执行,它就可以移植。第二个问题的答案是,表达式依赖于负整数的表示
为了回答第一个问题,由于算术表达式依赖于数据类型及其表示形式,因此我认为没有一个单独的算术表达式可以等同于表达式I&-I
。本质上,下面的代码在功能上等同于该表达式。(假设i
是int
类型)请注意,我必须使用循环来生成相同的功能,而不仅仅是算术
int tmp = 0, k = 0;
while(tmp < 32)
{
if(i & (1 << tmp))
{
k = i & (1 << tmp);
break;
}
tmp++;
}
i += k;
inttmp=0,k=0;
而(tmp<32)
{
如果(i&(1在2的补码结构上,使用4位有符号整数:
| i | bin | comp | -i | i&-i | dec |
+----+------+------+----+------+-----+
| 0 | 0000 | 0000 | -0 | 0000 | 0 |
| 1 | 0001 | 1111 | -1 | 0001 | 1 |
| 2 | 0010 | 1110 | -2 | 0010 | 2 |
| 3 | 0011 | 1101 | -3 | 0001 | 1 |
| 4 | 0100 | 1100 | -4 | 0100 | 4 |
| 5 | 0101 | 1011 | -5 | 0001 | 1 |
| 6 | 0110 | 1010 | -6 | 0010 | 2 |
| 7 | 0111 | 1001 | -7 | 0001 | 1 |
| -8 | 1000 | 1000 | -8 | 1000 | 8 |
| -7 | 1001 | 0111 | 7 | 0001 | 1 |
| -6 | 1010 | 0110 | 6 | 0010 | 2 |
| -5 | 1011 | 0101 | 5 | 0001 | 1 |
| -4 | 1100 | 0100 | 4 | 0100 | 4 |
| -3 | 1101 | 0011 | 3 | 0001 | 1 |
| -2 | 1110 | 0010 | 2 | 0010 | 2 |
| -1 | 1111 | 0001 | 1 | 0001 | 1 |
备注:
您可以推测i&-i
只有一个位集(它是2的幂),并且它与i
的最低有效位集相匹配
i+(i&-i)
有一个有趣的特性,就是更接近2的下一次幂
i+=(i&-i)
设置i
的最低有效未设置位
因此,做i+=(i&-i);
最终会让你跳到下一个二次幂:
| i | i&-i | sum | | i | i&-i | sum |
+---+------+-----+ +---+------+-----+
| 1 | 1 | 2 | | 5 | 1 | 6 |
| 2 | 2 | 4 | | 6 | 2 | -8 |
| 4 | 4 | -8 | |-8 | -8 | UB |
|-8 | -8 | UB |
| i | i&-i | sum | | i | i&-i | sum |
+---+------+-----+ +---+------+-----+
| 3 | 1 | 4 | | 7 | 1 | -8 |
| 4 | 4 | -8 | |-8 | -8 | UB |
|-8 | -8 | UB |
UB:有符号整数的溢出表现出未定义的行为。以下是我根据其他答案所做的研究。位操作
i -= (i&-i); // strips off the LSB (least-significant bit)
i += (i&-i); // adds the LSB
主要用于遍历a。特别是,i&-i
给出LSB,如果有符号整数通过表示。正如他最初的建议中所述,这不适用于其他有符号整数表示。但是
i &= i-1; // strips off the LSB
is(它也可以与和表示一起使用),并且少了一个操作
然而,似乎没有简单的便携式替代品来添加LSB。最简单的方法是从数学等价性的角度来考虑它:
-i == (~i + 1)
因此-i
将值的位反转,然后添加1
。其意义在于-i
的所有低位0
位通过-i
操作转换为1
s,因此向值添加1
会导致所有低位1
位翻转为0
向上移动1
,直到它落在0
位,刚好与i
中最低的1
位处于同一位置
下面是数字6(二进制0110)的示例:
在意识到位中的模式之前,您可能需要手动执行每个操作几次
这里还有两个例子:
i = 1000
~i == 0111
(~i + 1) == 1000
i & (~i + 1) == 1000
i = 1100
~i == 0011
(~i + 1) == 0100
i & (~i + 1) == 0100
查看+1
如何导致一种“位级联”,将其带到第一个打开的0
位
因此,如果(i&-i)
是提取最低1
位的一种方法,那么i+=(i&-i)
和i-=(i&-i)
的用例都是尝试对值的最低1位进行加减
将值的最低1位从其自身中减去可将该位归零
将值的最低1位添加到其本身似乎没有任何特殊用途,它只是按照tin上的说明执行
它应该可以在任何使用2的补码的系统上移植。如果i
具有无符号类型,则表达式可以完全移植并定义良好
如果i
有符号类型,它就不可移植,因为&
是根据表示定义的,而一元-
,+=
和-=
是根据值定义的。但是,如果
在无符号情况下(以及两位补码情况下),很容易确认i&-i
是二的幂(只有一位非零),并且与i
的最低位(也是-i
的最低位)具有相同的值。因此:
i-=i&-i;
清除i
的最低设置位
i+=i&-i;
增加i
的最低设定位(清除,但带进位到较高的位)
对于无符号类型,两个表达式都不会溢出。对于有符号类型,当i
最初具有类型的最小值时,i-=i&-i
溢出,当i
最初具有类型的最大值时,i+=i&-i
溢出,i&-i
为i
的连续值形成一个分形图案,例如:0 1 2 1 4 1 2 1 8 1 4 1 1 1 2 1 16 2 1 4…
希望这篇文章能帮到你。这篇文章解释得很好。@Walter,它对我很有用
i = 1000
~i == 0111
(~i + 1) == 1000
i & (~i + 1) == 1000
i = 1100
~i == 0011
(~i + 1) == 0100
i & (~i + 1) == 0100