【问题标题】:Signed and unsigned right shift seem to have the same behaviour有符号和无符号右移似乎具有相同的行为
【发布时间】:2019-05-08 17:30:38
【问题描述】:

为什么无符号右移(逻辑右移)和有符号右移(算术右移)对负数产生相同的结果?

Log.v("-59 >>> 5 expected 6, actual", String.valueOf((byte)(-59 >>> 5)));
Log.v("11000101 >>> 5 expected 00000110, actual",Integer.toBinaryString( -59 >>> 5));
Log.v("11000101 >> 5 expected 00000110, actual",Integer.toBinaryString( -59 >> 5));

Android Studio Logcat 输出

-59 >>> 5 expected 6, actual: -2

11000101 >>> 5 expected 00000110, actual: 111111111111111111111111110

11000101 >> 5 expected 00000110, actual: 11111111111111111111111111111110

【问题讨论】:

  • "这是一个 java VM 错误" 这不应该是你的第一个假设。请解释你为什么期望你所期望的。
  • "为什么和有符号右移一样?"它不是。 111111111111111111111111110 != 11111111111111111111111111111110(计算前导 1)。
  • 而 int 是 32 位的,而不是您认为的 8 位...
  • -59 的二进制表示为 11000101,当它在逻辑上向右移动时,结果应该是 00000110,即十进制 6。但是当我使用 >>> 运算符时,我得到 -2 相当于 11111110 .这表明已完成有符号右移,而不是逻辑移位。

标签: java


【解决方案1】:

这是正常行为。任何具有负值的整数都具有以无限 1 开头的二进制表示。

所以如果你开始说:-3 二进制表示看起来像这样:

...11 1101

所以如果我们把它右移 2 我们得到

...11 1111

现在是无符号/有符号的右移。这取决于我们的整数中没有无限位的事实。假设我们有一个分配为 -3 的 8 位整数,它看起来像这样:

1111 1101

如果我们进行有符号移位,它将查看 MSB(最高有效位,最左边的一位)并在移位时保留该值。因此,带符号的右移 3 如下所示:

1111 1111

相反,无符号右移不会检查 MSB,只是右移并填充零,结果如下:

0011 1111

这正是您所看到的,但输出截断了前面的零。


如果你不知道为什么负整数会这样存储,check this answer


至于为什么(b & 0xff) >>> 5的行为不同

Java 中的整数是 32 位的,这意味着二进制表示将有 32 位。你的 -59 看起来像下面的二进制表示:

1111 1111 1111 1111 1111 1111 1100 0101 == -59
0000 0111 1111 1111 1111 1111 1111 1110 == -59 >>> 5

如果您现在并且将其与0xff 一起使用,您将获得以下信息:

1111 1111 1111 1111 1111 1111 1100 0101 == -59
0000 0000 0000 0000 0000 0000 1111 1111 == 0xff
0000 0000 0000 0000 0000 0000 1100 0101 == -59 & 0xff
0000 0000 0000 0000 0000 0000 0000 0110 == (-59 & 0xff) >>> 5

【讨论】:

    【解决方案2】:

    右移运算符:- 如果数字为负数,则用 1 填充。如果数字为正数,则用 0 填充。 无符号移位运算符:- 无论数字的符号如何,它都填充为 0。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      • 1970-01-01
      相关资源
      最近更新 更多