我正在研究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);
那么,是否意味着逻辑右移将考虑溢出位?
答案 0 :(得分:3)
对于足够大的low
和high
值,表达式会溢出是正确的。如果其中一个值为负数,则可能会得到错误的结果。
但是,您不能在二进制搜索方法中获得负数,因为low
和high
都是数组的索引;他们必须是积极的。因此,加法的结果只会溢出到符号位;它不会创建一个进位。
由于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。