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


78

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


9
Python没有内置的无符号类型。
BrenBarn

2
您可以使用abs()函数。
Ali SAID OMAR

2
另外,您要解决的问题是什么?
BrenBarn

1
Python的整数类型具有无限的精度,并且不依赖于基础固定大小类型。因此,它无法区分无符号和有符号类型。您将必须自己进行转换。

4
@AliSAIDOMAR不,abs函数不能提供(unsigned)C中(uint32_t)a = (1LL << 32) - a
强制转换

Answers:


98

假设

  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

unsigned long在运行此示例的盒子上,C恰好是4个字节。


48
我不知道您可以_用来引用上一行的结果!
Yay295 '18

@ Yay295对!这是否仅在交互模式下可行?还是可以在非交互模式下使用?
HelloGoodbye

1
@HelloGoodbye,"_"用于检索以前的结果,不是语言本身的功能,而是某些(大多数?全部?)交互式Python shell实现的便利。为了显示它,他们无论如何都必须获取最新的结果。语言本身没有做到这一点。
蒂姆·彼得斯

万一其他人迷失了这个答案,我建议您查看@Duncan的答案,它将所有Python整数转换为unsigned long等效值。我认为,简单地添加2 ** 32或1 << 32仅适用于一定范围内的负整数。
比尔

68

要获得与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,则此逆过程将使值保持不变,但显然这不是真正的逆,因为如果您以不适合掩码大小的值开头,则这些位将消失。


+一:简单,没有进口
切赫Vepřek

1
为什么在地球上这项工作有效?(以及什么是逆运算)
MB。

2
@MB我扩展了答案,希望能有所帮助。
邓肯'18

事实证明倒数很有用。一些用C编写的python库返回一个有符号的64bit值,并且最终在python中使用了很长的时间
user1978816 '19

16

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


4

您可以使用structPython内置库:

编码:

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体系结构中,int并且long是32位的,因此您可以分别使用iI代替land L

1

python没有内置将int转换为unsigned int的内置函数,取而代之的是更长的范围。

>>> val = 9223372036854775807 (maximum value of int 64)
>>> type(val)
<type 'int'>
>>> val += 1
>>> type(val)
<type 'long'>

通过将val的值增加1,我超过了有符号64位整数的限制,并且该值转换为long。如果Python使用或转换为无符号整数,则val仍然是int。或者,不长。

有符号整数由一个位(通常是最高有效位)表示,对于正数设置为0,对于负数设置为1。val&0xff所做的实际上是val&0x000000ff(在32位计算机上)。换句话说,将有符号位设置为0,并模拟无符号值。

一个例子:

>>> val = -1
>>> val & 0xff
255

0

只是使用abs将无符号转换为python

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

输出:12


我觉得这只是部分正确。由于python MDN状态>abs() 返回数字的绝对值。该参数可以是一个普通或长整数或浮点数。如果参数为复数,则返回其大小。根据定义,这并不总是返回unsigned变量
Samuel Hulla '18

但是他只要求整数。
哈里·普拉索

0

从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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.