操作员>>称为右移 ,将所有位右移指定的次数。 重要的是>>填充最左边的符号位(最高有效位MSB)到最左边的位后移。 这就是所谓的符号扩展 ,当你把它们移到正确的位置时,它可以保留负数的符号 。
下面是我的示意图,用一个例子来说明这是如何工作的(对于一个字节):
例:
i = -5 >> 3; shift bits right three time
5的补码forms是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 ,五个是一个字节是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中知道更多的右移运算符是有用的>>>称为无符号右移 。 它在逻辑上工作并且从每次换class操作的左侧填充零。 因此,在每次右移时,如果对正负数都使用无符号右移>>>运算符,则总是会在最左边的位置得到一个零位。
例:
i = -5 >>> 3; Unsigned shift bits right three time
下面是我的图演示如何expression式-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
你可以注意到:这一次我不写符号位传播,但实际上>>>运算符插入零。 因此>>>不会保留符号,而是做逻辑右移。
据我所知,无符号右移在VDU(graphics编程)中是有用的,尽pipe我没有使用它,但是在过去的某些地方读过它。
我build议你阅读这个: >>>和>>之间的区别 : >>是算术右移, >>>是逻辑右移。
编辑 :
一些有趣的关于无符号右移运算符>>>运算符。
无符号的右移运算符>>>产生一个纯粹的值,它的左操作数右移0 0扩展右操作数指定的位数。
像>>和<< ,运算符>>>运算符也不会抛出exception。
无符号右移运算符的每个操作数的types必须是整型数据types,否则会发生编译时错误。
>>>操作符可以对其操作数执行types转换; 与算术二元运算符不同,每个操作数都是独立转换的。 如果操作数的types是byte,short或char,则在计算运算符的值之前,将该操作数转换为int。
无符号右移运算符生成的值的types是其左操作数的types。 LEFT_OPERAND >>> RHIGT_OPERAND
如果左操作数的转换types是int,则只有右操作数值的五个最低有效位用作移位距离。 ( 即2 5 = 32位= int中的位数 )
所以移动距离在0到31之间。
这里, r >>> s产生的值与下面的一样:
s==0 ? r : (r >> s) & ~(-1<
如果左操作数的types很长,那么只有右操作数值的6个最低有效位被用作移位距离( 即2 5 = 64位=长位数 )
这里, r >>> s产生的值与下面相同:
s==0 ? r : (r >> s) & ~(-1<
一个有趣的参考: [第4章] 4.7移位运算符