二进制 +1 -1迷思

原码

计算机是二进制的世界,需要用二进制表示我们所熟知的十进制数字。浮点数更存在一些无法用二进制完美表示的十进制数字,这是二进制计算机的limitions也是数值计算中需要注意的点。

e.g. 1的4位原码表示 0b0001(省去符号位,同下文)

反码

通常意义上讲,反码指的是按位取反。

e.g. 0b0001 的反码 0b1110

补码

计算机中,x+y减法运算被x+(-y)的补码运算代替,以减少额外电路设计,仅用加法器运算加减法。

e.g. 4-2 = 4+(-2) -> 0b0100 + 0b1110 = 0b0010

注意此处 0b1110 就是补码即2按位取反+1

思考为什么补码要+1,十进制中0是一个特殊数字,其原码是0b0000 反码0b1111, 补码是0b0000(高位舍去1)。问题出在0的补码,加0运算保持原结果,那么直接用0b1111与任意数字加法运算与十进制不对应,解决这个问题很简单,0的补码就是其本身,负数的二进制编码+1(如-2 -> 0b1110)来充当补码。这样,所有-运算可以用+补码替代。

x & -x -> 最后一位1的位置

就在上述十进制的二进制编码规则下,产生了一些特殊的位运算规律。

e.g. 2 & -2 -> 0b0010 & 0b1110 = 0b0010 ->最后一位1的位置

x & (x-1) -> 将最后一位1置0

e.g.

2 & (2-1) -> 0b0010 & 0b0001 = 0b0000 = 0 ->将最后一位1置0

3 & (3-1) -> 0b0011 & 0b0010 = 0b0010 = 2 ->将最后一位1置0

反码+1为补码(对比Python ~x = -x-1),x & -x x & (x-1) 二进制中+1 -1的操作可以这样有趣。

Python intToBin32 or bin32ToInt

def intToBin32(i):
    return (bin(((1 << 32) - 1) & i)[2:]).zfill(32)

def bin32ToInt(s):
    return int(s, 2)
    # if signed int, int(s[1:], 2)- int(s[0]) * (1 << 31)