Java的:关于负数右移(Java: right shift on negative number)

2019-07-21 19:06发布

我对负数右移操作很困惑,这里是代码。

int n = -15;
System.out.println(Integer.toBinaryString(n));
int mask = n >> 31;
System.out.println(Integer.toBinaryString(mask));

其结果是:

11111111111111111111111111110001
11111111111111111111111111111111

为什么通过31不为1(符号位)向右移位一个负数?

Answer 1:

由于在Java中没有无符号的数据类型,有两种类型的右移: 算术移位 >>和逻辑移位 >>> 。 http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

算术移位>>将保持符号位。

无符号移位>>>不会保留符号位(从而填充0或多个)。

(维基百科图像)


顺便说一句,这两个算术左移和逻辑左移有同样的结果,所以只有一个左移<<



Answer 2:

操作>>签名右移 ,转移所有位权的指定次数。 重要的是>>罢了,最左边的符号位(最高有效位MSB)到最左边的位后移。 这就是所谓的符号扩展 ,并用来保护当你转移他们的权利负数的符号

下面是我用一个例子图示来说明其工作原理(一个字节):

例:

i = -5 >> 3;  shift bits right three time 

五补的形式是1111 1011

内存中表示:

 MSB
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 0 | 1 | 1 |   
+----+----+----+---+---+---+---+---+
   7    6   5    4   3   2   1   0  
  ^  This seventh, the left most bit is SIGN bit  

并在下文中,如何>>工作的? 当你-5 >> 3

                        this 3 bits are shifted 
                         out and loss
 MSB                   (___________)      
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 0 | 1 | 1 |   
+----+----+----+---+---+---+---+---+
  | \                 \  
  |  ------------|     ----------|
  |              |               |
  ▼              ▼               ▼
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 1 | 1 | 1 |
+----+----+----+---+---+---+---+---+
(______________)
 The sign is        
 propagated

注意:最左边的三位是一个因为每个班次符号位是保留的,每个位是正确的了。 我写的符号被传播 ,因为所有这三位是因为符号(而不是数据)。

也正因为三个右移最右边的三位是亏损的。

右侧的两个箭头之间的比特被从先前的位在暴露-5

我认为这将是很好的,如果我写一个例子为正数了。 在下一个例子中是5 >> 3和5是一个字节是0000 0101

                        this 3 bits are shifted 
                         out and loss
 MSB                   (___________)      
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 1 | 0 | 1 |   
+----+----+----+---+---+---+---+---+
  | \                 \  
  |  ------------|     ----------|
  |              |               |
  ▼              ▼               ▼
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 0 | 0 |
+----+----+----+---+---+---+---+---+
(______________)
 The sign is        
 propagated

见我又写符号传播 ,所以,最左边的三个零是由于签位。

因此,这是运营商>> 签名右移做,保留左操作数的符号。

[你的答案]
在代码中,你换班-15到适合31使用时间>>操作让你的最右边的31位松动和结果的所有位1 ,实际上是-1的幅度。

你是否注意到这样-1 >> n等同于不声明。
我相信如果一个人做i = -1 >> n应该进行优化, i = -1由Java编译,但那是另一回事

接下来,这将是有趣的在Java中了解一个更向右移位运算符可用>>>称为无符号右移 。 和它的作品在逻辑上和左零填充每个班次运行。 因此,在每次右移你总是得到最左边的位置零位,如果你使用无符号右移>>>运营商都正数和负数。

例:

i = -5 >>> 3;  Unsigned shift bits right three time 

以下是我的图表,演示了如何表达-5 >>> 3作品?

                        this 3 bits are shifted 
                         out and loss
 MSB                   (___________)      
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 0 | 1 | 1 |   
+----+----+----+---+---+---+---+---+
  | \                 \  
  |  ------------|     ----------|
  |              |               |
  ▼              ▼               ▼
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 1 | 1 | 1 | 1 | 1 |
+----+----+----+---+---+---+---+---+
(______________)
  These zeros
  are inserted  

你可以注意到:这次我不写那个传播符号位,但实际上>>>操作插入零。 因此>>>不蜜饯签署,而不是做逻辑右移。

在我的知识无符号右移是在视频显示器(图形程序)是有用的,虽然我还没有使用它,但读它在过去的某个地方。

我建议你阅读本: 区别>>>和>>>>是算术右移, >>>为逻辑右移。

编辑

一些有趣的关于无符号右移运算符>>>运营商。

  • 无符号的向右移位运算符>>>产生一个纯值,该值是它的左操作数右移用零0通过其右操作数中指定的比特数扩展。

  • >><< ,操作>>>还运算符从不抛出异常。

  • 类型无符号的向右移位运算的每个操作数的必须是整数数据类型,或编译时会出现误差。

  • 所述>>>操作者可以在其操作数执行类型转换; 不像算术二元操作,每个操作数独立地转换。 如果操作数的类型是字节,短,或焦炭,计算操作者的值之前该操作数转换为int。

  • 类型由无符号向右移位运算符产生的值是它的左操作数的类型。 LEFT_OPERAND >>> RHIGT_OPERAND

  • 如果转换类型的左操作数的数据类型为int,只有五个 右操作数的值中的至少显著位用作移位距离。 ( 即2 5 = 32位=在int位的数量
    所以,移位距离至31的范围是从0。

    这里,通过所产生的值r >>> s是一样的:

     s==0 ? r : (r >> s) & ~(-1<<(32-s)) 
  • 如果左操作数的类型是长,则只有六个最右边的操作数的值的显著位用作移位距离。( 即2 5 = 64位=在长位的数量

    这里,通过所产生的值r >>> s是相同的,如下所示:

     s==0 ? r : (r >> s) & ~(-1<<(64-s)) 

甲有趣的参考: [第4章] 4.7移位操作符



Answer 3:

因为>>被定义为一个算术右移,它保留符号。 为了得到你所期望的效果,使用逻辑右移,在>>>运营商。



文章来源: Java: right shift on negative number