为什么在Java(高+低)/ 2错误但(高+低)>>> 1不是?

我理解>>>修复溢出:当添加两个大的正长数时,你可能会得到一个负数。 有人可以解释这种按位转换如何神奇地修复溢出问题吗? 它与>>什么不同?


我怀疑:我认为这与Java使用两个赞美这一事实有关,所以如果我们有额外的空间,但溢出是正确的数字,但是因为我们没有变成负面。 所以当你移动并用零划桨时,它会因为两个赞美而神奇地得到修复。 但我可能是错的,有点大脑的人必须证实。 🙂

简而言之, (high + low) >>> 1是一种技巧,它使用未使用的符号位来执行非负数的正确平均值。


highlow均为非负的假设下,我们确信最高位(符号位)为零。

因此, highlow都是31位整数。

 high = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824 low = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824 

当您将它们添加到一起时,它们可能会“溢出”到顶部位。

 high + low = 1000 0000 0000 0000 0000 0000 0000 0000 = 2147483648 as unsigned 32-bit integer = -2147483648 as signed 32-bit integer (high + low) / 2 = 1100 0000 0000 0000 0000 0000 0000 0000 = -1073741824 (high + low) >>> 1 = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824 
  • 作为带符号的32位整数,它是溢出的并且翻转为负。 因此(high + low) / 2是错误的,因为high + low可能是负的。

  • 作为无符号32位整数,总和是正确的。 所需要的只是将它除以2。

当然Java不支持无符号整数,所以我们必须除以2(作为无符号整数)的最好的事情是逻辑右移>>>

在具有无符号整数的语言(例如C和C ++)中,由于输入可以是完整的32位整数,因此它会变得更加棘手。 一种解决方案是: low + ((high - low) / 2)


最后列举>>>>>/之间的区别:

  • >>>是合乎逻辑的右移。 它用零填充高位。
  • >>是算术右移。 它上面填充了原始顶部位的副本。
  • /是分裂。

数学:

  • x >>> 1x视为无符号整数,并将其除以2。 它向下舍入。
  • x >> 1x视为有符号整数并将其除以2。 它朝向负无穷大。
  • x / 2x视为有符号整数,并将其除以2。 它向零舍入。

它填充最顶部的位而不是填充符号。

 int a = 0x40000000; (a + a) / 2 == 0xC0000000; (a + a) >>> 1 == 0x40000000; 

我建议阅读Joch Bloch的http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html#!/2006/06/extra-extra-read-关于高低的所有关于它的几乎所有

“我为JDK编写的二进制搜索版本包含了同样的错误。最近有人向Sun报告,在等待了9年左右之后它破坏了某人的程序。”