这是一种使用 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 开头,所有负数都以 1 开头。我们需要稍微修改一下,以确保-2**n 形式的数字只会得到一个前导一位,我们通过在计算位长时将所有负数加 1 来做到这一点。
要选择我们想要的位,我们需要一个适当长度的位掩码。如果位长为 4,我们想要一个掩码 1111 = 2**4 - 1;我们可以使用求幂来计算它,但使用位移更有效:(1 << bitlen) - 1。然后我们执行按位与运算n & mask 来选择我们想要的位。幸运的是,当我们执行这样的屏蔽操作时,Python 给了我们一个非负数。 :)
最后,我们使用.format 方法将结果整数转换为字符串。我们使用嵌套格式规范,因此我们可以动态指定输出字符串的正确长度。在
'{0:0{1}b}'.format(n & mask, bitlen)
格式规范的第一个 0 表示我们正在转换参数列表中 0 arg 的值 (n & mask),:0{1}b 表示将其转换为二进制,必要时用前导零填充,使用参数列表 (bitlen) 中 1 arg 的值作为总字符串长度。
您可以在文档的Format String Syntax 部分阅读有关嵌套格式规范的信息:
format_spec 字段还可以包含嵌套的替换字段
在其中。这些嵌套的替换字段可能包含一个字段名称,
转换标志和格式规范,但不是更深的嵌套
允许。 format_spec 中的替换字段是
在解释 format_spec 字符串之前替换。这
允许动态指定值的格式。