Python可以保存无限的整数值,位表示将适应任何你输入的数字。因此,在这个上下文中,二进制补码等技术细节是没有意义的。在C语言中,'b1111111111111111'表示int16为-1,uint16或int32为65535。而在Python中,它始终是65535,因为int类型会适应保存这样的值。
我认为这就是为什么他们选择在负数前面加上“-”,而不管字符串表示形式是二进制、八进制、十六进制还是十进制。
如果你希望复制C语言的行为,并以二进制补码形式表示负数,你有以下几个选项:
1. 使用numpy进行int > uint > bin转换
最直接的方法是将值转换为有符号的有限整数,然后将其作为无符号整数读取。
如果你可以使用numpy,代码非常容易阅读:
>>> bin(np.int16(-30).astype(np.uint16))
'0b1111111111100010'
>>> bin(np.int16(-1).astype(np.uint16))
'0b1111111111111111'
>>> bin(np.int16(-2).astype(np.uint16))
'0b1111111111111110'
>>> bin(np.int16(-16).astype(np.uint16))
'0b1111111111110000'
使用结构体将2个int转为uint再转为二进制
你也可以使用结构体来完成类似的操作,但是这可能会稍微难理解一些。
>>> bin(struct.unpack('>H', struct.pack('>h', 30))[0])
'0b1111111111100010'
>>> bin(struct.unpack('>H', struct.pack('>h', -1))[0])
'0b1111111111111111'
>>> bin(struct.unpack('>H', struct.pack('>h', -2))[0])
'0b1111111111111110'
>>> bin(struct.unpack('>H', struct.pack('>h', -16))[0])
'0b1111111111110000'
注意:h是有符号的,H是无符号的16位整数,“>”代表大端序,如果你想直接读取字节而不将它们转换回整数,它非常方便。
3. 使用结构体进行int转换,然后逐字节读取并转换为二进制。
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -1<<15))
'1000000000000000'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -1))
'1111111111111111'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -2))
'1111111111111110'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -16))
'1111111111110000'
请注意,这里有一些小问题,因为您需要记住使用“08”来强制字节二进制表示为8位数字。
3 直接从数学上讲
最后,您可以查看维基百科关于二进制补码表示的内容,并直接从数学公式二进制补码 > 从2N中减去中实现它。
>>> bin(2**16 -16)
'0b1111111111110000'
>>> bin(2**16 -3)
'0b1111111111111101'
这个看起来超级简单,但如果你不熟悉二进制补码表示的工作方式,就很难理解。