二进制 +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)