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