【问题标题】:Python Bitwise Inverse Not Flipping BitsPython按位反转不翻转位
【发布时间】:2020-04-15 11:03:37
【问题描述】:

当使用 pythons inverse ~ 时,似乎这些位没有像我预期的那样翻转。我相信困惑在于我对 python 如何使用 2 的恭维存储数字的理解。

myInt = 5 #101
inverse = ~myInt
print(bin(inverse))

输出:-0b110

预期:-0b010 或 -0b10

【问题讨论】:

标签: python bit


【解决方案1】:

这不是 ~ 运算符的问题,它可以做它应该做的事情,而是使用您用来显示结果的 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 的整数没有预定义的位长。它们不是 16 位或 32 位长,就像 C 中的 shortlong 整数一样。相反,它们是动态调整大小的,根据需要添加更多位以表示越来越大的数字。当您需要将二进制数字表示为文本时(如 bin 函数所做的那样),这会导致一个棘手的情况。如果您知道您的号码仅使用 16 位,您可以每次都写出一个 16 位的字符串,但动态大小的号码需要不同的解决方案。

确实,Python 在bin 函数中做了一些不同的事情。正数用表示其值所需的最短位数写入。负数不是用二进制补码写的(它们实际上是在内部编码的方式),而是在它们的绝对值的位表示之前放一个减号。

所以你得到一个这样的表,其中按位补码不明显:

 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() 的负数感到失望。最重要的是,您不能对其进行按位运算。谢谢。
【解决方案2】:

这与two's complement 编码负数的方式有关。任何整数的负数表示都是通过反转数字和加一来计算的。

如果您翻转该逻辑,反转二进制表示将否定该值并减去一个。所以 5 的倒数确实应该是 -6。

~5                                                                                                                                                                                                                                  
# -6

由于 Python 不为每个整数使用固定位数,因此无法显示所有前导零(有无限个数)。所以前面有一个负号,-0b110 代表-6

选择任意固定位数,你可以写出不带负数的二进制数。例如使用 8 位(一个字节),它将是 1111 1010,这与您预期的相反。

【讨论】:

    【解决方案3】:

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

    一般来说,Python 整数的~x 等于-x - 1(等效于-(x+1))。这对于 Python 代码很少有用,但你永远不知道 :)

    【讨论】:

      【解决方案4】:

      你是对的 - 这种行为确实与 Python 在 twos-complement 中存储负数的方式有关。在幕后,否定一个数字,将(有效)无限的前导列表附加到二进制表示中。因此,虽然bin(6)0b110,但bin(-6) 实际上是0b010(您可以通过观察bin(-6 &amp; 7) = 0b010 来了解这一点。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-16
        • 2011-03-12
        • 2022-04-28
        • 2022-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多