go中的算术移位
使用代码统计给定整型值中 1 的个数时,对于负数,发现程序会陷入死循环。思考后发现,go 语言中进行算术移位时,如果操作数为负数,移位后结果最终会停留到-1
。
使用代码统计给定整型值中 1 的个数时,陷入死循环的代码:
for xor != 0 {
xor >>= 1
if xor&1 == 0 {
count++
}
}
go 中整型数的移位采用算术移位。关于逻辑移位与算术移位,对比如下:
左移低位补位(不溢出前提下) | 右移高位补位 | |
---|---|---|
算术移位 | 补 0 | 补 0 |
逻辑移位 | 低位补 0 | 符号位不变,使用符号位补最高位 |
根据补位规则,当操作数为负数时,最终值为-1
,所以代码会陷入死循环。
统计数字比特位中 1 个数时,以下代码更加通用:
for xor != 0 {
xor &= xor - 1
count++
}
代码中xor &= xor - 1
可去除xor
中的最低位1
比特位。其原理如下:
补码的提出,就是为了将+
和-
操作都统一转换为+
操作以方便计算机进行计算。所以将代码中xor - 1
转换为xor + (-1)
。-1
在机器中的补码存储形式为0x1111....1111
。假设 xor 形式为0x.... 0100
,xor + (-1)
结果为0x.... 0011
。最低位1
左边其余比特位均保持不变,右边比特位均变为0
。将xor
与xor + (-1)
结果异或,则可将最低位1
去除。
该方法通过避免使用移位操作,避免了算术移位过程中引入的多余符号位,进而避免程序陷入死循环。