Python技巧:负数的16进制补码
最近控制仪器需要输入负数的补码,本来以为挺复杂,请教了AI,发现Python输出补码如此简单:
def negative_to_32bit_hex(num):if num >= 0:raise ValueError("输入必须为负数")# 计算32位补码(Python自动处理大整数)hex_str = hex(num & 0xFFFFFFFF)return hex_strif __name__ == "__main__":try:num = int(input("请输入一个负整数(如-7500): "))result = negative_to_32bit_hex(num)print(f"32位补码(16进制): {result}")except ValueError as e:print(f"错误: {e}")
在Python中,(-1 & 0xFF) 能够正确输出 -1 的 8位补码 形式(即 0xFF),是因为 位运算(&)会直接操作整数的二进制表示,而 不关心其符号。以下是详细解释:
1. 补码的概念
- 补码(Two's Complement) 是计算机中表示有符号整数的常见方式:
- 正数:补码 = 原码(直接二进制表示)。
- 负数:补码 = 绝对值的二进制表示 取反后加1(或等价于:模 2n 下的同余表示)。
- 例如,8位补码:
+1=00000001-1=11111111(因为-1 ≡ 255 mod 256,即0xFF)
2. -1 & 0xFF 的运算过程
(1)-1 的二进制表示
Python的整数是任意精度的,但位运算会隐式截断到操作数的位宽:
-1的二进制补码形式是 无限长的1(因为-1 = ~0,即对0按位取反):...11111111111111111111111111111111
(2)0xFF 的作用
0xFF是 8位掩码(二进制11111111),用于截取-1的低8位:-1 & 0xFF = ...11111111 & 0000000011111111 = 11111111 (0xFF)- 这相当于计算
-1 mod 256(因为 (2^8 = 256)),结果是255(即0xFF)。
(3)为什么这是补码?
- 在8位系统中,
0xFF被解释为:- 无符号整数:
255 - 有符号补码整数:
-1(因为最高位是1,表示负数,其值 =value - 256=255 - 256 = -1)
- 无符号整数:
3. Python的 hex() 函数
hex()直接输出整数的十六进制形式,不区分符号:pythonhex(255) # 输出 '0xff'- 由于
-1 & 0xFF的结果是255(即0xFF),所以hex()输出0xff,这恰好是-1的8位补码表示。
4. 推广到其他位宽
类似地,可以通过调整掩码的位数来获取不同位宽的补码:
python
# 16位补码 |
(-1 & 0xFFFF) # 输出 65535 (0xFFFF) |
# 32位补码 |
(-1 & 0xFFFFFFFF) # 输出 4294967295 (0xFFFFFFFF) |
# 64位补码 |
(-1 & 0xFFFFFFFFFFFFFFFF) # 输出 18446744073709551615 (0xFFFFFFFFFFFFFFFF) |
5. 关键点总结
- 位运算截断:
& 0xFF会丢弃-1的高位,只保留低8位(即0xFF)。 - 补码等价性:在8位系统中,
0xFF既是255的无符号表示,也是-1的补码表示。 - Python的整数:Python不区分有符号/无符号,但位运算和
hex()的输出可以模拟补码行为。
6. 验证补码的正确性
可以通过以下代码验证 0xFF 是否是 -1 的8位补码:
python
# 将0xFF转换为有符号8位整数 |
def to_signed_8bit(n): |
return (n & 0xFF) - 256 if (n & 0x80) else (n & 0xFF) |
print(to_signed_8bit(0xFF)) # 输出 -1 |
- 如果最高位(第8位)是1,则值为
n - 256,否则为n。
结论
(-1 & 0xFF) 通过 掩码运算 截取 -1 的低8位,得到 0xFF(即 255),而 hex(255) 输出 0xff,这恰好是 -1 的8位补码表示。这种方法可以推广到任意位宽(如16位、32位等)。
