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去除。
该方法通过避免使用移位操作,避免了算术移位过程中引入的多余符号位,进而避免程序陷入死循环。