按位运算一元〜(反转)

问题描述 投票:0回答:6

我对

~
运算符有点困惑。代码如下:

a = 1
~a  #-2
b = 15
~b  #-16

~
如何发挥作用?

我想,

~a
会是这样的:

0001 = a
1110 = ~a 

为什么不呢?

python bit-manipulation
6个回答
76
投票

你说得完全正确。它是补码整数表示的产物。

在 16 位中,1 表示为

0000 0000 0000 0001
。反转后,您会得到
1111 1111 1111 1110
,即 -2。同样,15 是
0000 0000 0000 1111
。倒过来,你得到
1111 1111 1111 0000
,即 -16。

一般来说,

~n = -n - 1


38
投票

“~”运算符定义为: “x 的按位反转定义为 -(x+1)。它仅适用于整数。”Python Doc - 5.5

这句话的重要部分是,这与“整数”(也称为整数)有关。您的示例代表一个 4 位数字。

'0001' = 1 

4位数字的整数范围是'-8..0..7'。另一方面,您可以使用“无符号整数”,不包括负数,并且 4 位数字的范围为“0..15”。

由于 Python 对整数进行操作,因此您所描述的行为是预期的。整数使用二进制补码表示。如果是 4 位数字,则如下所示。

 7 = '0111'
 0 = '0000'
-1 = '1111'
-8 = '1000'

如果您有 32 位操作系统,Python 使用 32 位进行整数表示。您可以使用以下方法检查最大整数:

sys.maxint # (2^31)-1 for my system

如果您希望为您返回 4 位数字的无符号整数,则必须进行掩码。

'0001' = a   # unsigned '1' / integer '1'
'1110' = ~a  # unsigned '14' / integer -2

(~a & 0xF) # returns 14

如果您想获得无符号 8 位数字范围 (0..255),只需使用:

(~a & 0xFF) # returns 254

25
投票

看起来我找到了更简单的解决方案,可以实现所需的功能:

uint8: x ^ 0xFF
uint16: x ^ 0xFFFF
uint32: x ^ 0xFFFFFFFF
uint64: x ^ 0xFFFFFFFFFFFFFFFF

8
投票

您还可以使用无符号整数(例如来自 numpy 包)来实现预期的行为。

>>> import numpy as np
>>> bin( ~ np.uint8(1))
'0b11111110'

0
投票

问题是应用 ~ 的结果所表示的数字没有明确定义,因为它取决于用于表示原始值的位数。例如:

5 = 101
~5 = 010 = 2

5 = 0101
~5 = 1010 = 10

5 = 00101
~5 = 11010 = 26

但是,两者的补码 ~5 在所有情况下都是相同的:

two_complement(~101) = 2^3 - 2 = 6
two_complement(~0101) = 2^4 - 10 = 6
two_complement(~00101) = 2^5 - 26 = 6

鉴于二进制补码用于表示负值,因此将 ~5 视为其补码的负值 -6 是有意义的。

因此,更正式地说,为了达到这个结果,我们有:

  1. 翻转零和一(相当于取补码)
  2. 取二进制补码
  3. 应用负号

如果 x 是 n 位数字:

~x = - two_complement(one_complement(x)) = - two_complement(2^n - 1 - x) = - (2^n - (2^n - 1 - x)) = - (x + 1)

0
投票

对于任何想要在整数的二进制表示中进行语义反转位数字的人来说,这是一个实现,例如

0b110010
->
0b1101
而不是
0b110010
->
-0b110011
~
运算符一样。

def bit_invert(n: int) -> int:
    """Calculate the bitwise inverse of n.

    Doesn't do funky stuff with sign bits, like Python's built-in bitwise not.
    """
    return n ^ ((1 << n.bit_length()) - 1)

示例

>>> for i in range(16):
...     print(i, bin(i), bin(bit_invert(i)))
... 
0 0b0 0b0
1 0b1 0b0
2 0b10 0b1
3 0b11 0b0
4 0b100 0b11
5 0b101 0b10
6 0b110 0b1
7 0b111 0b0
8 0b1000 0b111
9 0b1001 0b110
10 0b1010 0b101
11 0b1011 0b100
12 0b1100 0b11
13 0b1101 0b10
14 0b1110 0b1
15 0b1111 0b0
© www.soinside.com 2019 - 2024. All rights reserved.