两个补语的Python(尽可能少的位)

时间:2016-11-01 17:35:14

标签: python python-3.x binary

我试图输出负数的二进制表示,每次可用的字节数最少。

示例:

-3 -> 101
-10 -> 10110

1 个答案:

答案 0 :(得分:4)

这是使用Python 3整数的.bit_length方法执行此操作的方法。它还使用字符串.format方法进行整数到二进制字符串转换。对于非负数,此函数返回以'0'开头的字符串,以便可以将它们与负数区分开来。

def twos_complement(n):
    m = n + 1 if n < 0 else n
    bitlen = 1 + m.bit_length()
    mask = (1 << bitlen) - 1
    return '{0:0{1}b}'.format(n & mask, bitlen)

for i in (-10, -3, 0, 3, 10):
    print('{:3}: {}'.format(i, twos_complement(i)))

print('- ' * 30)

for i in range(-15, 16):
    print(i, twos_complement(i))    

<强>输出

-10: 10110
 -3: 101
  0: 0
  3: 011
 10: 01010
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
-15 10001
-14 10010
-13 10011
-12 10100
-11 10101
-10 10110
-9 10111
-8 1000
-7 1001
-6 1010
-5 1011
-4 100
-3 101
-2 10
-1 1
0 0
1 01
2 010
3 011
4 0100
5 0101
6 0110
7 0111
8 01000
9 01001
10 01010
11 01011
12 01100
13 01101
14 01110
15 01111

如何运作

Python使用二进制补码的修改形式来表示整数。 Python整数没有大小限制,因此负整数的行为就像它们具有无限前导1位数一样,如Python Wiki article on Bitwise Operators中所述。

int.bit_length方法告诉我们表示数字所需的最小位数,我们想要多一位,这样我们所有的非负数都将从0开始,所有负数都以a开头1.我们需要稍微修改一下以确保-2**n形式的数字只能获得一个前导位,我们通过在计算位长时将所有负数加1来实现。

要选择我们想要的位,我们需要一个适当长度的位掩码。如果位长为4,我们需要一个1111 = 2**4 - 1的掩码;我们可以通过使用取幂来计算它,但使用位移更有效:(1 << bitlen) - 1。然后我们按位AND运算n & mask来选择我们想要的位。幸运的是,当我们执行这样的屏蔽操作时,Python会给我们一个非负数。 :)

最后,我们使用.format方法将结果整数转换为字符串。我们使用嵌套格式规范,因此我们可以动态指定输出字符串的正确长度。在

'{0:0{1}b}'.format(n & mask, bitlen) 

格式规范的前0表示我们正在转换参数列表中的0 arg的值(n & mask),:0{1}b表示将其转换为二进制,填充带有前导如有必要,使用参数列表中的1 arg的值(bitlen)作为总字符串长度。

您可以在文档的Format String Syntax部分阅读有关嵌套格式规范的信息:

  

format_spec 字段还可以包含嵌套的替换字段   在其中。这些嵌套的替换字段可能包含字段名称,   转换标志和格式规范,但更深的嵌套不是   允许。 format_spec 中的替换字段是   在解释 format_spec 字符串之前替换。这个   允许动态指定值的格式。