【问题标题】:Java, will (low + high) >>> 1 overflow?Java,会(低+高)>>> 1溢出吗?
【发布时间】:2015-11-09 19:04:41
【问题描述】:

我正在研究 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) &gt;&gt;&gt; 1 不会溢出。 谁能告诉我为什么会这样?我用自己的代码测试它。

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

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

【问题讨论】:

  • &gt;&gt;&gt; 将值视为 32 位无符号整数,两个 31 位有符号整数之和不能大于 32 位无符号整数,因此不会出现溢出这个操作的。注意:如果您使用&gt;&gt;,您可能会遇到问题。

标签: java overflow


【解决方案1】:

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

但是,在二分查找方法中不能得到负数,因为lowhigh 都是数组的索引;他们必须是积极的。因此,加法的结果只会溢出到符号位;它不会产生进位。

由于 Java 的 &gt;&gt;&gt; 运算符将在没有符号扩展的情况下移动符号位,因此即使对于两个 Integer.MAX_VALUE,您也会得到正确的结果。从本质上讲,&gt;&gt;&gt; 运算符让您可以将第 32 位视为无符号存储的额外位,即使该位属于有符号类型。

【讨论】:

    【解决方案2】:

    如果low + high 的结果溢出并变为负数,则(low + high) / 2(low + high) &gt;&gt; 1 都不起作用。

    a &gt;&gt; 1 保留原始的符号位,因此a 的负值给出负结果

    a &gt;&gt;&gt; 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 了解适用于正值和负值的表达式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-20
      • 2023-01-30
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 2015-11-05
      • 2012-12-01
      相关资源
      最近更新 更多