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

时间:2013-12-24 21:14:55

标签: python integer unsigned signed

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

7 个答案:

答案 0 :(得分:70)

<强>假设

  1. 你有两个补充的表示;和,
  2. (unsigned long)表示无符号32位整数
  3. 然后您只需要将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个字节。

答案 1 :(得分:52)

要获得相当于C cast的值,只需按位并使用适当的掩码。例如如果unsigned long是32位:

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

或如果它是64位:

>>> i & 0xffffffffffffffff
18446744073702667240

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

这是有效的,因为虽然Python看起来像将所有数字存储为符号和幅度,但按位运算被定义为处理两个补码值。 C以二进制补码存储整数但具有固定位数。 Python按位运算符作用于二进制补码值,但好像它们具有无限数量的位:对于正数,它们用零向左延伸到无穷大,但负数向左延伸用1。 &运算符会将左边的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,此逆过程将保持值不变,但显然它不是真正的逆,因为如果您开始使用的值不适合掩码大小,则这些位将消失。 / p>

答案 2 :(得分:13)

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

答案 3 :(得分:1)

您可以使用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代替l和{{1 }} 分别。

答案 4 :(得分:0)

只需使用abs将python中的未签名转换为已签名

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

输出:    12

答案 5 :(得分:0)

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

答案 6 :(得分: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