如何在python中将有符号整数转换为无符号整数

新手上路,请多包涵

假设我有这个号码 i = -6884376 。我如何将其称为无符号变量?像 (unsigned long)i 在 C 中。

原文由 Lior 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

假设

  1. 你心中有 2 的补码表示;和,
  2. 通过 (unsigned long) 你的 意思是 无符号 32 位整数,

那么你只需要将 2**32 (or 1 << 32) 添加到负值。

例如,将其应用于 -1:

 >>> -1
-1
>>> _ + 2**32
4294967295L
>>> bin(_)
'0b11111111111111111111111111111111'

假设 #1 意味着您希望 -1 被视为 1 位的实心字符串,而假设 #2 意味着您想要其中的 32 个。

但是,除了您之外,没有人可以说出您隐藏的假设是什么。例如,如果您有 1 的补码表示,那么您需要改为应用 ~ 前缀运算符。 Python 整数努力给出使用无限宽的 2 的补码表示的错觉(就像常规的 2 的补码,但具有无限数量的“符号位”)。

要复制平台 C 编译器的功能,您可以使用 ctypes 模块:

 >>> import ctypes
>>> ctypes.c_ulong(-1)  # stuff Python's -1 into a C unsigned long
c_ulong(4294967295L)
>>> _.value
4294967295L

C 的 unsigned long 恰好是运行该样本的盒子上的 4 个字节。

原文由 Tim Peters 发布,翻译遵循 CC BY-SA 3.0 许可协议

要获得与 C 转换等效的值,只需按位并使用适当的掩码即可。例如,如果 unsigned long 是 32 位:

 >>> i = -6884376
>>> i & 0xffffffff
4288082920

或者如果它是 64 位:

 >>> i & 0xffffffffffffffff
18446744073702667240

请注意,虽然这给了你在 C 中的值,但它仍然是一个带符号的值,因此任何后续计算都可能给出负结果,你将不得不继续应用掩码来模拟 32 或 64位计算。

这是可行的,因为尽管 Python 看起来将所有数字存储为符号和大小,但按位运算被定义为处理二进制补码值。 C 以二进制补码形式存储整数,但位数是固定的。 Python 按位运算符作用于二进制补码值,但就好像它们具有无限多的位数:对于正数,它们向左扩展到零为无穷大,但负数向左扩展为一。 & 运算符会将左边的一串变成零,只剩下适合 C 值的位。

以十六进制显示值可能会使这一点更清楚(我将 f 的字符串重写为表达式以表明我们对 32 位或 64 位感兴趣):

 >>> hex(i)
'-0x690c18'
>>> hex (i & ((1 << 32) - 1))
'0xff96f3e8'
>>> hex (i & ((1 << 64) - 1)
'0xffffffffff96f3e8L'

对于 C 中的 32 位值,正数最高为 2147483647 (0x7fffffff),负数的最高位设置为 -1 (0xffffffff) 至 -2147483648 (0x80000000)。对于完全适合掩码的值,我们可以通过使用较小的掩码移除符号位然后减去符号位来反转 Python 中的过程:

 >>> u = i & ((1 << 32) - 1)
>>> (u & ((1 << 31) - 1)) - (u & (1 << 31))
-6884376

或者对于 64 位版本:

 >>> u = 18446744073702667240
>>> (u & ((1 << 63) - 1)) - (u & (1 << 63))
-6884376

如果符号位为 0,此逆过程将保持值不变,但显然它不是真正的逆过程,因为如果您以不适合掩码大小的值开始,那么这些位就会消失。

原文由 Duncan 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题