如何在python中将负整数值转换为十六进制
Posted
技术标签:
【中文标题】如何在python中将负整数值转换为十六进制【英文标题】:how to convert negative integer value to hex in python 【发布时间】:2011-12-10 23:58:03 【问题描述】:我使用 python 2.6
>>> hex(-199703103)
'-0xbe73a3f'
>>> hex(199703103)
'0xbe73a3f'
正负值一样吗?
当我使用 calc 时,值为FFFFFFFFF418C5C1
。
【问题讨论】:
【参考方案1】:Python 的整数可以任意增长。为了以您想要的方式计算原始two's-complement,您需要指定所需的位宽。您的示例以 64 位二进制补码显示 -199703103
,但它也可能是 32 位或 128 位,导致开头的 0xf
数量不同。
hex()
不这样做。我建议以下作为替代方案:
def tohex(val, nbits):
return hex((val + (1 << nbits)) % (1 << nbits))
print tohex(-199703103, 64)
print tohex(199703103, 64)
打印出来:
0xfffffffff418c5c1L
0xbe73a3fL
【讨论】:
能否解释一下添加(1<<64)
时发生的情况?为什么需要这样做?
@jathanism,(1<<64)
的值比 64 位整数大一。将其添加到负数将使其变为正数,只要负数适合 64 位。如果原始数字是正数,%
将撤消添加的效果。
我相信这个实现有一个bug:tohex(-129,8)返回0x7f,这是不可能的,因为8位有符号整数只能存储来自(-1)*(2 ^7)= -128 到 2^7 - 1 = 127。因此该函数应在返回之前检查 val 是否在此范围内,如果不在此范围内,则引发异常(或其他情况)。我认为这可以使代码更健壮:)【参考方案2】:
因为 Python 整数是任意大的,所以您必须屏蔽这些值以将转换限制为您想要的 2s 补码表示的位数。
>>> hex(-199703103 & (2**32-1)) # 32-bit
'0xf418c5c1L'
>>> hex(-199703103 & (2**64-1)) # 64-bit
'0xfffffffff418c5c1L'
Python 将 hex(-199703103)
的简单情况显示为负十六进制值 (-0xbe73a3f
),因为 2s 补码表示在其前面将有无限数量的 Fs 用于任意精度数。掩码值 (2**32-1 == 0xFFFFFFFF) 限制了这一点:
FFF...FFFFFFFFFFFFFFFFFFFFFFFFF418c5c1
& FFFFFFFF
--------------------------------------
F418c5c1
【讨论】:
虽然简洁,但与位操作相比,升权不是成本高吗? @swdev,py -m timeit "2**32-1"
-> 每个循环 0.0235 微秒,py -m timeit "2<<32-1"
-> 每个循环 0.0235 微秒。不要假设。如果您关心,请务必测量 :) Python 字节编译器很可能会生成相同的加载常量。
哎呀,让(1<<32)-1
...但你明白了...也更容易犯错误。我检查了dis
模块,Python 只生成了一个常量。
如果您担心时间问题,您也可以使用常量0xFFFFFFFF
来代替2**32-1
32 位和0xFFFFFFFFFFFFFFFF
64 位。或mask_32bit=(2**32-1)
这样您就不必每次都进行计算,只需一次。
@busfault 每个评论上面的速度没有什么不同。 Python 在生成字节码时计算一次常量。无需“优化”。【参考方案3】:
添加到Marks answer,如果您想要不同的输出格式,请使用
':X'.format(-199703103 & (2**32-1))
【讨论】:
【参考方案4】:对于那些想要正数前导零的人,试试这个:
val = 42
nbits = 16
':04X'.format(val & ((1 << nbits)-1))
感谢@tm1 的启发!
【讨论】:
':0X'.format(val & ((1 << nbits)-1), int((nbits+3)/4))
将正确设置宽度。以上是关于如何在python中将负整数值转换为十六进制的主要内容,如果未能解决你的问题,请参考以下文章