位运算 x & -x 表示含义
一、原码反码补码
在计算机中,整数的数据的存储是按照补码的方式进行存储的
按照数据与0的大小,数据又被分为正数与负数
- 正数的原码反码补码相同。
- 负数的原码,反码,补码并不相同。它们之间的转换关系如下:
- 负数的反码:该负数的原码除符号位外各位取反。
- 负数的补码:负数的反码 + 1
我们来看下面的一个例子理解原码反码补码的求解:
[+1] = [00000001]原 = [00000001]反 = [00000001]补 [-1] = [10000001]原 = [11111110]反 = [11111111]补
通过上面的例子我们可以知道:
在计算机中取一个数 x(可正可负)的相反数,其实也就等价于:这个数的补码的基础上进行按位取反(包括符号位)之后在增加1
即:-x = (~x) +1
二、位运算 x & -x 表示含义
下面我们来讨论: 位运算 x & -x
表示含义
当x
为奇数时:
例如: x = 3
x = 3 // 00000000 00000000 00000000 00000011 补码 -x // 11111111 11111111 11111111 11111101 补码 ret = x & -x //00000000 00000000 00000000 00000011 补码 //11111111 11111111 11111111 11111101 补码 ret //00000000 00000000 00000000 00000001 补码
可以看到对于一个奇数如果执行表达式ret = x & -x
那么得到的结果是1
,如果你不相信,你还可以试一试其他奇数。
原理分析:
对于一个奇数 x,其比特位最后一位(最右边的那一位)一定是1
,对这个奇数x取相反数也就相当于按位取反然后加一,奇数按位取反以后最后一位一定是0
,然后+1
后最后一位一定是1
,但是 -x 除了最后一位与 x 相同,其余均不同,于是x & -x
的结果一定是 1。
举例:
[+1]// 00000001 奇数的最后一位一定是1 [-1]// 11111111 相反数是 按位取反 然后 +1, 导致最后一位与原数相等
当x
为偶数时:
例如 x = 4
x = 6 // 00000000 00000000 00000000 00000110 补码 -x // 11111111 11111111 11111111 11111001 反码 // 11111111 11111111 11111111 11111010 补码 ret = x & -x // 00000000 00000000 00000000 00000110 补码 // 11111111 11111111 11111111 11111010 补码 ret // 00000000 00000000 00000000 00000010 补码
观察结果ret
我们会发现:
- 这个结果只有一位值是1, 其他位均是0 ,而且这个值为
1
的位置是与原数 x 从右向左第一个比特位为1
的位置相同- 这个值的末位0的个数与原值 x 保持一致
原理分析:
- 原数 x 最低非0位右边所有的0,经由取反后全部变为1,反码+1会导致这些1逐位发生进位并变为0,最终进位记到最低非0位。
- 原最低非0位是1,取反后是0,进位到这一位0变成1,不再向左进位
- 原最低非0位左边的每一位经由取反后 和 原码 进行与运算必为0
三、最终结论
当一个数与其相反数相与(&):
如果这个数是奇数, 则结果必为1(这个1
的位置与原数的最低非零位位置相同)。
如果这个数是偶数, 则结果是一个特殊的数据,与原数据的最低非零位相同位置为1
,其他位置全为0
。
用途: 一般可以用来获取某个二进制数的最低非零位