Java中的按位右移运算符

时间:2014-07-29 16:41:03

标签: java bit-manipulation bitwise-operators

在Java中,-4>> 2给出-1但-5>> 2给-2。谁能解释为什么? 以下是示例代码:

byte r=-5;
r>>=2;
System.out.println(r);

同样在这种情况下>>和>>>运营商给出了相同的答案。任何人都可以解释一下吗?

5 个答案:

答案 0 :(得分:5)

你可以看一下这些位。使用two's complement表示法,-4-5的位是,为简洁起见仅显示最后8位:

-4: 1111 1100      
-5: 1111 1011

位移到右侧2位置,带符号扩展名:

-4 >> 2: 1111 1111 (-1)
-5 >> 2: 1111 1110 (-2)

通常情况下,您认为>>>没有使用符号扩展名,这是正确的,但在这种情况下:

r >>>= 2;

...对于使用二进制数字提升的位移操作,值r被提升为int,但是复合赋值运算符将返回的值转换回byte,并且移入的零"消失"。

byte r = -5;     // 1111 1100
r >>>= -2;       // promoted to int:   11111111 11111111 11111111 11111010
                 // bit shift:         00111111 11111111 11111111 11111110
                 // cast back to byte: 11111110 (-2)

JLS, Section 15.26.2,讨论了在复合赋值运算符中完成的转换操作:

  

E1 op = E2形式的复合赋值表达式等效于E1 =(T)((E1)op(E2)),其中T是E1的类型,但E1仅被评估一次。

也就是说,在这种情况下,位移的结果被转换回byte

r的值为-4时,会发生相同的强制回送操作。

请注意,如果分配部分尚未完成,那么您将看不到相同的答案,因为它不会将结果强制转换回byte

System.out.println(r >>> 2);

然后你会看到:

1073741822

答案 1 :(得分:2)

  

任何人都可以解释为什么(-4>>> 2是-1,-5>> 2是-2)?

二进制-4字节如下所示:11111100。当你在扩展符号的同时向右移动时,你得到11111111(左边的是符号扩展,即在向左移动时保持符号位)。这是两个补码表示中的-1

二进制-5字节如下所示:11111011。当你在伸出标志的同时向右移动时,你会得到11111110(同样,左边的是符号扩展名)。这是-2。

  

>>>>>运营商给出相同的答案。任何人都可以解释一下吗?

移位以整数执行。当您使用>>>转换-4 而不使用符号扩展名时,您会获得00111111111111111111111111111111。当您将其转换为byte时,您会切断前24位,最后将低8位全部设置为1。同样适用于>>>的{​​{1}}。

答案 2 :(得分:0)

字节-4 == 0xFC。如果将算术右移(即保留符号位)2位,则得到0xFF,即-1。

-5 == 0xFB。如果将算术右移2位,则得到0xFE,即-2。

答案 3 :(得分:0)

在负数的情况下,在内存中,它们使用称为二进制补码的技术进行存储。在这个例子中,5是:0 ... 0101(我为了长度而删除了很多0 所以当你转移0101两次时,你得到:

0101 >> 0010
0010 >> 0001

0001是1

在二进制补码中你有1 ... 1011(反向所有位然后加一个二进制1) 所以当你转移1011时你已经

1011 >> 1101 (we carry the other 1's)
1101 >> 1110 (we carry the other 1's)

1 ... 1110是-2

的负数

答案 4 :(得分:0)

Java使用二进制补码格式来表示负数。

-5表示为二进制的11111011,当右位移位2位时变为11111110,即-2。类似地,-4表示为11111100,当右位移2时变为11111111,十进制为-1。

>>>>>看起来相同的原因是因为>>>运算符是整数的逻辑右移,而不是字节。因此,java在执行逻辑移位之前将类型转换为int,然后将bitstring截断为仅最低有效8位。因为-5的整数表示是11111111111111111111111111111011而右边的逻辑移位2是11111111111111111111111111111110,它是11111110的字节的类型转换,即-2。

如果您尝试以下代码,则会看到结果:

byte r = -5;
System.out.println(r >> 2);
System.out.println(r >>> 2);
r>>>=2;
System.out.println(r);