假设我有这个号码i = -6884376
。我如何将其称为无符号变量?像(unsigned long)i
C一样
abs
函数不能提供(unsigned)
C中(uint32_t)a = (1LL << 32) - a
的
假设我有这个号码i = -6884376
。我如何将其称为无符号变量?像(unsigned long)i
C一样
abs
函数不能提供(unsigned)
C中(uint32_t)a = (1LL << 32) - a
的
Answers:
假设:
(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个字节。
_
用来引用上一行的结果!
"_"
用于检索以前的结果,不是语言本身的功能,而是某些(大多数?全部?)交互式Python shell实现的便利。为了显示它,他们无论如何都必须获取最新的结果。语言本身没有做到这一点。
unsigned long
等效值。我认为,简单地添加2 ** 32或1 << 32仅适用于一定范围内的负整数。
要获得与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,则此逆过程将使值保持不变,但显然这不是真正的逆,因为如果您以不适合掩码大小的值开头,则这些位将消失。
您可以使用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
体系结构中,int
并且long
是32位的,因此您可以分别使用i
和I
代替l
and L
。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