位取反运算符

49

为什么位运算(~0);会输出-1?在二进制中,非0应该是1。为什么呢?


11
如果您想翻转单个位,请使用 x ^ 1 - kennytm
1
这不是一个“非”运算符,而是一个“补码”运算符。 - user207421
1
@EJP:一个一的补码运算符。 - kennytm
3
不是这样的。语言规范#4.2.2将"~"定义为"按位取反运算符"。在Java中,并不存在"位运算符 NOT"这个概念。 - user207421
1
@lh3:不是。在C和C++中,它是一元补码运算符。 - kennytm
10个回答

80

你其实已经非常接近了。

在二进制中,非0的数字应该是1.

没错,在我们谈论一个比特时,这绝对是正确的。

然而,一个值为0的整型实际上由32位全0组成!~会将所有32个零反转为32个一。

System.out.println(Integer.toBinaryString(~0));
// prints "11111111111111111111111111111111"

这是数字 -1 的二进制补码表示。

同样地:

System.out.println(Integer.toBinaryString(~1));
// prints "11111111111111111111111111111110"

换句话说,对于使用二进制补码表示的32位无符号int~1 == -2


进一步阅读:


13

您实际上表达的是0x00000000,这导致了0xFFFFFFFF。对于Java中的(有符号)int类型,这意味着-1。


9

您可以想象带符号数的第一位为 -(2x-1),其中x是位数。

因此,对于一个8位的数字,每个位(从左到右顺序)的值如下:

-128 64 32 16 8 4 2 1

现在,在二进制中,0显然是所有的0:

    -128 64 32 16 8 4 2 1
0      0  0  0  0 0 0 0 0 = 0

当您执行按位取反运算符~时,每个0都会变为1:

     -128 64 32 16 8 4 2 1
~0      1  1  1  1 1 1 1 1
 =   -128+64+32+16+8+4+2+1 == -1

这对于理解溢出也是有帮助的:

     -128 64 32 16 8 4 2 1
126     0  1  1  1 1 1 1 0  =  126
 +1     0  1  1  1 1 1 1 1  =  127
 +1     1  0  0  0 0 0 0 0  = -128  overflow!

8
~ 是一种位运算符。
~0 = 1 which is -1 in 2's complement form  

http://en.wikipedia.org/wiki/Two's_complement

以下是二进制补码形式的一些数字及其按位取反 ~(在它们下方):

0 1 1 1 1 1 1 1 = 127
1 0 0 0 0 0 0 0 = −128

0 1 1 1 1 1 1 0 = 126
1 0 0 0 0 0 0 1 = −127

1 1 1 1 1 1 1 1 = −1
0 0 0 0 0 0 0 0 = 0

1 1 1 1 1 1 1 0 = −2
0 0 0 0 0 0 0 1 = 1

1 0 0 0 0 0 0 1 = −127
0 1 1 1 1 1 1 0 = 126

1 0 0 0 0 0 0 0 = −128
0 1 1 1 1 1 1 1 = 127

注:二进制补码是一种用于表示带符号整数的方法。

一个清晰的例子就加了+1分。喜欢猜谜的程序员可以通过仔细研究你的例子了解~和二进制补码的工作原理! - Stijn de Witt

5

因为~不是二进制反转,而是按位反转。二进制反转应该使用!,并且只能(在Java中)应用于布尔值。


2

在标准的二进制编码中,0表示全为0,~表示按位取反。所有的1(通常情况下)对于有符号整数类型来说是-1。因此对于一个有符号字节类型:

0xFF = -1    // 1111 1111
0xFE = -2    // 1111 1110
...
0xF0 = -128  // 1000 0000
0x7F = 127   // 0111 1111
0x7E = 126   // 0111 1110
...
0x01 = 1     // 0000 0001
0x00 = 0     // 0000 0000

0

这是二进制反转,而在二补数中,-1是0的二进制反转。


0

这里的0不是一个位,而是一个字节(至少;或更多)- 00000000。使用按位或运算,我们将得到11111111。它作为有符号整数的值为-1...


0

对于32位有符号整数

~00000000000000000000000000000000=11111111111111111111111111111111 (即-1)


0

我认为真正的原因是波浪号(~)是二进制补码。

Javascript将字符波浪号(~)指定为二进制补码,尽管在大多数编程语言中,波浪号表示一的补码的位取反。


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