Python位运算取反、翻转位

4
使用Python的取反运算符~时,似乎比我预期的没有将位翻转。我相信混淆在于我的理解Python使用2的补码存储数字的方式。
myInt = 5 #101
inverse = ~myInt
print(bin(inverse))

输出结果:-0b110

期望结果:-0b010,或者-0b10


这个链接详细回答了你的问题:https://dev59.com/Y2w05IYBdhLWcg3wXQwh - Dhruv Agarwal
4个回答

3
这并不是与操作符~有关的问题,它执行的是应该执行的操作。相反,这是与你使用来显示结果的bin函数有关的问题。
在Python中,与大多数计算机系统一样,负整数以“二进制补码”表示。这意味着-1由所有1位的序列表示,并且每个较低的整数都通过常规整数减法规则修改该值。因此,-2通过从-1中减去1而形成,您会得到一堆1位,后面跟着一个零作为最后一位。
以下是一些数字及其4位二进制补码表示:
 0 : 0000
 1 : 0001
 2 : 0010
 5 : 0101
-1 : 1111  # this is ~0
-2 : 1110  # this is ~1
-3 : 1101  # this is ~2
-6 : 1010  # this is ~5

与许多其他编程语言不同,Python的整数没有预定义的位数。它们不像C语言中的shortlong整数那样是16位或32位长。相反,它们是动态大小的,需要更多的位来表示越来越大的数字。当您需要将二进制数字表示为文本(如bin函数所做的)时,这会导致棘手的情况。如果您知道您的数字仅使用16位,则每次都可以写出一个16位数字字符串,但动态大小的数字需要不同的解决方案。
事实上,在bin函数中,Python采用了一种不同的方法。正数以表示其值所需最少位数的方式进行编写。而负数则不是采用二进制补码(它们实际上是如何在内部编码的),而是在其绝对值的位表示前面放置一个减号。
因此,您会得到以下表格,其中比特位补码并不明显:
 0 :    0b0
 1 :    0b1
 2 :   0b10
 5 :  0b101
-1 :   -0b1
-2 :  -0b10
-3 :  -0b11
-6 : -0b110

对于如何获取类似第一张表中的负数的二进制表示,唯一好的方法是选择某个大于所有数字的2的幂次方,并在格式化之前将其添加到所有负值中:

MY_MAXINT = 2**4
for v in [0,1,2,5,-1,-2,-3,-6]:
    if v < 0:
        v += MY_MAXINT
    print(format(v, '04b'))

我对bin()函数处理负数的方式感到失望。此外,无法对其执行位运算。谢谢。 - Satbir Kira

1
这与二进制补码编码负数的方式有关。任何整数的负表示是通过反转数字并加一来计算的。
如果你把这个逻辑颠倒过来,反转一个二进制表示将会取反该值并减一。所以5的反向值确实应该是-6。
~5                                                                                                                                                                                                                                  
# -6

由于Python没有为每个整数使用固定数量的位,因此无法显示所有前导零(有无限多个)。因此,在前面加上负号,-0b110表示-6
选择任何固定数量的位,您都可以写出二进制数而不带负号。例如,对于8位(一个字节),它将是1111 1010,这是您预期的反向数。

0

由于Python具有任意大小的带符号整数,从概念上讲,它们被无限地扩展。当我们反转位0b101时,确实得到0b010,但是符号扩展也会翻转:数字以无限数量的1开头,而不是0。这个值1111111....1010等于-6,而不是-2,因为全1的值将是-1,然后我们减去4和1位。

一般来说,对于Python整数,~x等于-x - 1(或者等效地,-(x+1))。这在Python代码中很少使用,但是你永远不知道:)


0

你说得对 - 这种行为确实与Python如何在二进制补码中存储负数有关。在幕后,取反一个数字相当于在二进制表示中添加一个(实际上)无限的前导1列表。因此,虽然bin(6)0b110,但bin(-6)实际上是0b010(您可以通过观察bin(-6 & 7) = 0b010来看到这一点)。

这意味着使用~会做两件事情;它翻转二进制表示的第一位,然后再次翻转所有位。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接