Java,将(低+高)>>> 1溢出?

时间:2015-11-09 19:04:42

标签: java overflow

我正在研究Java 1.8 Api。 在java.util.Arrays.binarySearch(int[] a, int key)中,我找到了这段代码。

int low = fromIndex;
int high = toIndex - 1;

while (low <= high) {
    int mid = (low + high) >>> 1;
    int midVal = a[mid];

    if (midVal < key)
        low = mid + 1;
    else if (midVal > key)
        high = mid - 1;
    else
        return mid; // key found
}
return -(low + 1);  // key not found.

在这段代码(low + high) >>> 1中不会溢出。 谁能告诉我为什么会这样?我用我自己的代码测试它。

int low = Integer.MAX_VALUE;
int high = Integer.MAX_VALUE;
System.out.println((low + high) / 2);
System.out.println((low + high) >>> 1);

那么,是否意味着逻辑右移将考虑溢出位?

2 个答案:

答案 0 :(得分:3)

对于足够大的lowhigh值,表达式会溢出是正确的。如果其中一个值为负数,则可能会得到错误的结果。

但是,您不能在二进制搜索方法中获得负数,因为lowhigh都是数组的索引;他们必须是积极的。因此,加法的结果只会溢出到符号位;它不会创建一个进位。

由于Java的>>>运算符将在没有符号扩展名的情况下移位符号位,因此即使对于两个Integer.MAX_VALUE,也会获得正确的结果。实质上,>>>运算符允许您将第32位视为无符号存储的额外位,即使该位属于有符号类型。

答案 1 :(得分:0)

如果low + high的结果溢出并变为否定,则(low + high) / 2(low + high) >> 1都不起作用。

a >> 1保留原始符号位,因此a的负值会产生否定结果

a >>> 1通过引入零符号位来工作,因此任何a的结果都不会为负。

演示:

int low = 1;
int high = Integer.MAX_VALUE;
System.out.println(low + high);         // This is negative
System.out.println((low + high) >>> 1); // This is positive, and the desired result.
System.out.println((low + high) >> 1);  // This is negative
System.out.println((low + high) / 2);   // This is negative

由于溢出,找到两个int值的中间值很容易出错。有关适用于正值和负值的表达式,请参阅this question