我对负数右移操作很困惑,这里是代码。
int n = -15;
System.out.println(Integer.toBinaryString(n));
int mask = n >> 31;
System.out.println(Integer.toBinaryString(mask));
其结果是:
11111111111111111111111111110001
11111111111111111111111111111111
为什么通过31不为1(符号位)向右移位一个负数?
由于在Java中没有无符号的数据类型,有两种类型的右移: 算术移位 >>
和逻辑移位 >>>
。 http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
算术移位>>
将保持符号位。
无符号移位>>>
不会保留符号位(从而填充0
或多个)。
(维基百科图像)
顺便说一句,这两个算术左移和逻辑左移有同样的结果,所以只有一个左移<<
。
操作>>
叫签名右移 ,转移所有位权的指定次数。 重要的是>>
罢了,最左边的符号位(最高有效位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移位操作符
因为>>被定义为一个算术右移,它保留符号。 为了得到你所期望的效果,使用逻辑右移,在>>>运营商。