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

2019-07-04 19:19发布

我明白>>>修复溢出:增加了两个大的利好多头时,您可以用负数endup。 谁能解释这是如何按位移位神奇地修复了溢出的问题? 以及它是如何不同于>>


我纳闷:我认为它必须做的事实,Java使用两恭维所以溢出是正确的号码,如果我们有额外的空间,但因为我们不就变成负的。 所以,当你转移和桨零奇迹般地被固定,由于两恭维。 但我可能是错的,有人用按位大脑进行确认。 :)

Answer 1:

In short, (high + low) >>> 1 is a trick that uses the unused sign-bit to perform a correct average of non-negative numbers.


Under the assumption that high and low are both non-negative, we know for sure that the upper-most bit (the sign-bit) is zero.

So both high and low are in fact 31-bit integers.

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

When you add them together they may "spill" over into the top-bit.

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
  • As a signed 32-bit integer, it is overflow and flips negative. Therefore (high + low) / 2 is wrong because high + low could be negative.

  • As unsigned 32-bit integers, the sum is correct. All that's needed is to divide it by 2.

Of course Java doesn't support unsigned integers, so the best thing we have to divide by 2 (as an unsigned integer) is the logical right-shift >>>.

In languages with unsigned integers (such as C and C++), it gets trickier since your input can be full 32-bit integers. One solution is: low + ((high - low) / 2)


Finally to enumerate the differences between >>>, >>, and /:

  • >>> is logical right-shift. It fills the upper bits with zero.
  • >> is arithmetic right-shift. It fills the upper its with copies of the original top bit.
  • / is division.

Mathematically:

  • x >>> 1 treats x as an unsigned integer and divides it by two. It rounds down.
  • x >> 1 treats x as a signed integer and divides it by two. It rounds towards negative infinity.
  • x / 2 treats x as a signed integer and divides it by two. It rounds towards zero.


Answer 2:

它的零填充的,而不是标志填充他们的最顶层位。

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


Answer 3:

我建议你阅读Joch布洛赫的http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html#!/2006/06/extra-extra-read-所有关于-IT-nearly.html约高低

“二进制搜索的,我写的JDK版本包含相同的错误。据报道,Sun最近时,它打破了别人的方案,趴在等待了九年左右的时间。”



文章来源: Why in Java (high + low) / 2 is wrong but (high + low) >>> 1 is not?