Python中的两个补码二进制?

Tho*_*eia 36 python binary bit-manipulation

Python中的整数存储在两个补码中,对吗?

虽然:

>>> x = 5
>>> bin(x)
0b101
Run Code Online (Sandbox Code Playgroud)

和:

>>> x = -5
>>> bin(x)
-0b101
Run Code Online (Sandbox Code Playgroud)

那太蹩脚了.我怎么让python给我真正的二进制位数,而没有它的前面的0b?所以:

>>> x = 5
>>> bin(x)
0101
>>> y = -5
>>> bin(y)
1011
Run Code Online (Sandbox Code Playgroud)

tyl*_*erl 67

如果你提供面具,效果最好.这样你就可以指定签名扩展的距离.

>>> bin(-27 & 0b1111111111111111)
'0b1111111111100101'
Run Code Online (Sandbox Code Playgroud)

或者更一般地说:

def bindigits(n, bits):
    s = bin(n & int("1"*bits, 2))[2:]
    return ("{0:0>%s}" % (bits)).format(s)

>>> print bindigits(-31337, 24)
111111111000010110010111
Run Code Online (Sandbox Code Playgroud)

在基本理论中,数字的实际宽度是存储大小的函数.如果它是一个32位数字,那么负数在一组32的MSB中有1.如果它是64位值,那么有64位要显示.

但在Python中,整数精度仅限于硬件的约束.在我的电脑上,这实际上有效,但它只消耗9GB的RAM来存储x的值.任何更高的东西,我得到一个MemoryError.如果我有更多的RAM,我可以存储更大的数字.

>>> x = 1 << (1 << 36)
Run Code Online (Sandbox Code Playgroud)

那么考虑到这一点,二进制数代表-1什么?正如前面的例子所示,Python能够很好地解释数百万(甚至数十亿)的精度位.在2的补码中,符号位一直向左扩展,但在Python中没有预定义的位数; 你有多少需要.

但是你会遇到歧义:二进制1表示1,还是-1?好吧,也可能是.是否111代表7-1?同样,它也可能是.因此,根据您的精确度,111111111代表511或者-1......两者都是如此.

Python需要一种以二进制形式表示这些数字的方法,这样它们的含义就不存在歧义.该0b前缀只是说:"这个数字是用二进制".就像0x意思是"这个数字是十六进制".所以,如果我说0b1111,我怎么知道用户是想要-1还是15?有两种选择:

选项A: 符号位
您可以声明所有数字都是有符号的,最左边的位是符号位.这意味着0b1是-1,而它0b01是1.这也意味着它0b111也是-1,而0b01117是.最后,这可能比有用更令人困惑,特别是因为大多数二进制算术无论如何都是无符号的,人们更多可能会因意外地将数字标记为否定而导致错误,因为它们不包含明确的符号位.

选项B: 符号指示
使用此选项,二进制数表示无符号,负数表示" - "前缀,就像它们在十进制中一样.这是(a)与十进制更一致,(b)与最有可能使用二进制值的方式更兼容.您无法使用其二进制补码表示来指定负数,但请记住,二进制补码是存储实现细节,而不是基础值本身的正确指示.它不应该是用户必须理解的东西.

最后,选项B最有意义.混淆较少,用户无需了解存储详细信息.

  • +1,为了生成打印表示,这是最简单的方法。(不过请记住,`-27 &amp; 0b111111111` 的实际结果在内存中是一个正数!) (3认同)
  • 是的,但我的观点很简单,在内存中,“-27 &amp; 0b11111111”产生的值的最高有效位是零。(更一般地,如果操作数之一为正,则“&amp;”的结果将始终为正,因为正值被理解为前面有一个[无限的零字符串](http://wiki.python.org/ moin/按位运算符)。) (2认同)

cas*_*evh 14

为了将二进制序列正确地解释为二进制补码,需要与序列相关联的长度.在处理与CPU寄存器直接对应的低级类型时,存在隐式长度.由于Python整数可以具有任意长度,因此实际上没有内部二进制补码格式.由于没有与数字相关的长度,因此无法区分正数和负数.为了消除歧义,bin()在格式化负数时包含减号.

Python的任意长度整数类型实际上使用符号幅度内部格式.逻辑运算(位移,和/或等)旨在模仿二进制补码格式.这是多个精度库的典型特征.


小智 6

这是Tylerl 答案的一个更易读的版本,例如,假设您想要-2的“二进制补码”的8 位负表示形式:

bin(-2 & (2**8-1))
Run Code Online (Sandbox Code Playgroud)

2**8 代表第九位 (256),减去 1,前面的所有位都设置为 1 (255)

对于 8 位和 16 位掩码,您可以将 (2**8-1) 替换为 0xff 或 0xffff。此后,十六进制版本的可读性会降低。

如果这还不清楚,这里是它的常规函数​​:

def twosComplement (value, bitLength) :
    return bin(value & (2**bitLength - 1))
Run Code Online (Sandbox Code Playgroud)


Vic*_*hoy 6

The compliment of one minus number's meaning is mod value minus the positive value. So I think?the brief way for the compliment of -27 is

bin((1<<32) - 27)  // 32 bit length  '0b11111111111111111111111111100101'
bin((1<<16) - 27)
bin((1<<8) - 27)   // 8 bit length  '0b11100101'
Run Code Online (Sandbox Code Playgroud)


Jon*_*sco 5

不确定如何使用标准库获得你想要的东西。有一些脚本和软件包可以为您进行转换。

我只是想指出“为什么”,以及为什么它并不蹩脚。

bin() 不返回二进制位。它将数字转换为二进制字符串。前导的“0b”告诉解释器您正在处理一个二进制数,根据 python 语言的定义。这样你就可以直接使用二进制数,就像这样

>>> 0b01
1
>>> 0b10
2
>>> 0b11
3
>>> 0b01 + 0b10
3
Run Code Online (Sandbox Code Playgroud)

这并不蹩脚。那太棒了。


http://docs.python.org/library/functions.html#bin

箱(x)

将整数转换为二进制字符串。

http://docs.python.org/reference/lexical_analysis.html#integers

整数和长整数文字由以下词法定义描述:

bininteger ::= "0" ("b" | "B") bindigit+

bindigit ::= "0" | 二进制数字 “1”