了解无符号右移



JLS 15.19 描述了>>>运算符的公式。

n

>>> s 的值是 n 个右移的 s 位位置,具有 零扩展名,其中:

如果 n 为正,则结果与 n>> s 的结果相同。

如果 n 为负数且左操作数的类型为 int,则 结果等于表达式 (n>> s) + (2 <<~s) 的结果。

如果 n 为负数且左操作数的类型为长整型,则 结果等于表达式 (n>> s) + (2L <<~s) 的结果。

为什么n >>> s = (n >> s) + (2 << ~s) ,哪里~s = 31 - s int~s = 63 - s长?

如果n为负数,则表示设置了符号位。

>>> s意味着将s位置向右移动,将零引入空出的插槽中。

>> s意味着将s位置向右移动,将标志位的副本引入空出的插槽中。

例如

10111110000011111000001111100000 >>> 3 == 00010111110000011111000001111100
10111110000011111000001111100000 >>  3 == 11110111110000011111000001111100

显然,如果n不是负数,n >> sn >>> s是一样的。如果n为负数,则差值将由左侧的s个,后跟所有零组成。

换句话说:

(n >>> s) + X == n >> s        (*)

其中Xs 个 1 后跟 32 - s 个零组成。

因为X中有32 - s个零,所以X最右边的零出现在1 << (32 - s)中零的位置,等于2 << (31 - s),与2 << ~s相同(因为~s == -1 - s和移位量在int秒内功模32)。

现在,当您将2 << ~s添加到X时会发生什么?你得到零!让我们在案例中演示这一点 s == 7.请注意,进位从左侧消失。

  11111110000000000000000000000000
+ 00000010000000000000000000000000
  ________________________________
  00000000000000000000000000000000

因此,-X == 2 << ~s.因此,在(*)的两边都增加-X,我们得到

n >>> s == (n >> s) + (2 << ~s)

对于long来说,它是完全相同的,除了移位量是模 64,因为long有 64 位。

这里有一些额外的上下文,如果你还不知道他假设的基础知识,可以帮助你理解pbabcdefp的答案:

要理解按位运算符,您必须将数字视为二进制数字字符串,例如。 20 = 00010100-4 = 11111100(为了清楚起见,不必写那么多数字,我将把所有二进制数写成byte s; int s相同,但长度是其四倍)。如果您不熟悉二进制和二进制操作,可以在此处阅读更多内容。注意第一个数字的特殊之处:它使数字为负数,就好像它有一个位值(还记得初等数学,一个/十/几百个位?)最负数,所以Byte.MIN_VALUE = -128 = 1000000,将任何其他位设置为 1 总是会增加数字。要轻松读取负数,例如 11110011 ,知道-1 = 11111111,然后读取 0,就好像它们是正数中的 1,那么该数字就是您与 -1 的距离。所以11110011 = -1 - 00001100 = -1 - 12 = -13.

还要了解~s是按位 NOT 的:它获取所有数字并翻转它们,这实际上相当于 ~s = -1 - s .例如~5 (00000101)-6 (11111010)。观察我建议的读取负二进制数的方法如何只是一个技巧,能够读取数字的按位 NOT 而不是数字本身,这对于接近零的负数更容易,因为这些数字的 0 秒比 1 秒少。

最新更新