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

Posted

技术标签:

【中文标题】如何在python中将有符号整数转换为无符号整数【英文标题】:How to convert signed to unsigned integer in python 【发布时间】:2014-01-13 01:05:54 【问题描述】:

假设我有这个号码i = -6884376。 我如何将它称为无符号变量? 类似于 C 中的 (unsigned long)i

【问题讨论】:

Python 没有内置的无符号类型。 你可以使用 abs() 函数。 另外,您这样做是为了解决什么问题? Python 的整数类型具有无限精度,并且不依赖于底层的固定大小类型。因此,它无法区分无符号和有符号类型。您必须自己进行转换。 @AliSAIDOMAR 不,abs 函数没有提供 (unsigned) 转换在 C 中为您提供的内容,即 (uint32_t)a = (1LL << 32) - a 用于 2 的补码 【参考方案1】:

从 3.2 版开始:

def toSigned(n, byte_count): 
  return int.from_bytes(n.to_bytes(byte_count, 'little'), 'little', signed=True)

输出:

In [8]: toSigned(5, 1)                                                                                                                                                                                                                                                                                                     
Out[8]: 5

In [9]: toSigned(0xff, 1)                                                                                                                                                                                                                                                                                                  
Out[9]: -1

【讨论】:

对我来说,这是迄今为止最 Pythonic 的方法。它甚至允许初学者友好的字节打包/解包,并检查输入,如果它甚至可以用给定数量的字节等等来表示。请参阅docs.python.org/3/library/stdtypes.html int.from_bytes 和 int.to_bytes 了解更多信息。【参考方案2】:

您可以使用struct Python 内置库:

编码:

import struct

i = -6884376
print('0:b'.format(i))

packed = struct.pack('>l', i)  # Packing a long number.
unpacked = struct.unpack('>L', packed)[0]  # Unpacking a packed long number to unsigned long
print(unpacked)
print('0:b'.format(unpacked))

输出:

-11010010000110000011000
4288082920
11111111100101101111001111101000

解码:

dec_pack = struct.pack('>L', unpacked)  # Packing an unsigned long number.
dec_unpack = struct.unpack('>l', dec_pack)[0]  # Unpacking a packed unsigned long number to long (revert action).
print(dec_unpack)

输出:

-6884376

[注意]:

> 是 BigEndian 操作。 l 很长。 L 是无符号长整数。 在amd64 架构中intlong 是32 位的,因此您可以分别使用iI 而不是lL

【讨论】:

【参考方案3】:

只需使用abs将无符号转换为python中的签名

 a=-12
b=abs(a)
print(b)

输出: 12

【讨论】:

我觉得这只是部分正确。正如python MDN 状态 > abs() 返回一个数字的绝对值。参数可以是普通整数或长整数或浮点数。如果参数是复数,则返回其大小。 根据定义,这不会一直返回 unsigned 变量 但他只要求整数。 这不是(unsigned long)i 所做的。这是完全错误的。 unsigned 与 abs 非常不同。无符号只是通过不考虑要签名的第一位来改变读取一组位值的方式。另一方面,abs 将有符号位更改为未设置(通过采用 2 的补码),从而更改位表示【参考方案4】:

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

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

或者如果是 64 位:

>>> i & 0xffffffffffffffff
18446744073702667240

请注意,尽管这为您提供了 C 中的值,但它仍然是一个有符号值,因此任何后续计算都可能给出否定结果,您必须继续应用掩码来模拟32 位或 64 位计算。

这是可行的,因为尽管 Python 看起来将所有数字都存储为符号和大小,但按位运算被定义为处理二进制补码值。 C 以二进制补码形式存储整数,但位数固定。 Python 位运算符作用于二进制补码值,但好像它们有无限数量的位:对于正数,它们向左延伸到无穷大,零,但负数向左延伸。 & 运算符会将左侧的一串 1 更改为零,并只留下适合 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,此逆过程将保持值不变,但显然它不是真正的逆过程,因为如果您从不适合掩码大小的值开始,那么这些位将消失。

【讨论】:

+一:简单,无导入 为什么这行得通? (以及什么是逆运算) @MB 我扩展了我的答案,希望对您有所帮助。 逆向证明非常有用。一些用 C 编写的 python 库返回一个有符号的 64 位值,这在 python 中以 long 结束【参考方案5】:

假设

    您已经想到了 2 的补码表示;并且, (unsigned long)意思是无符号 32 位整数,

那么你只需要在负值上加上2**32 (or 1 &lt;&lt; 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 个字节。

【讨论】:

我不知道你可以使用_来引用上一行的结果! @Yay295 对!这只能在交互模式下使用还是也可以在非交互模式下使用? @HelloGoodbye,使用"_" 检索先前的结果并不是语言本身的特性,而是一些(大多数?全部?)交互式 Python shell 实现的便利。无论如何,他们必须获取最新的结果才能显示它。语言本身并没有这样的事情。 以防万一其他人偶然发现这个答案,我建议查看@Duncan's answer instead,它将任何Python整数转换为unsigned long等价物。我认为只需添加 2**32 或 1 @Bill,不过我更喜欢这个答案。如果被屏蔽的位不是全部(概念上无限的副本字符串)符号位,则链接到的答案隐藏了可能的错误。这里的答案在愚蠢的情况下留下了一个看起来很愚蠢的结果;-) 例如,-1000000 &amp; 0xff 返回 192,没有留下任何信息丢失的线索(结果总是适合 8 位)。但是-1000000 + 256 返回 -999744,这是一个明确的线索,如果您认为不会丢失任何有意义的位,就会出现问题。 YMMV。【参考方案6】:

Python 没有内置的无符号类型。您可以使用数学运算来计算一个 new int 表示您将在 C 中获得的值,但没有 Python int 的“无符号值”。 Python int 是整数值的抽象,而不是对固定字节大小整数的直接访问。

【讨论】:

以上是关于如何在python中将有符号整数转换为无符号整数的主要内容,如果未能解决你的问题,请参考以下文章

在 python 中将 HEX 转换为无符号 INT16 [重复]

在C#中是否可以在没有类型转换的情况下将整数转换为无符号整数? [关闭]

如何使用 SSE 将 _m128i 转换为无符号整数?

将 4 个字节转换为无符号 32 位整数并将其存储在 long

如何在 AVX2 中将 32 位无符号整数转换为 16 位无符号整数?

将小端序列中的4个字节转换为无符号整数