【问题标题】:Midpoint Formula Overflow Error中点公式溢出错误
【发布时间】:2014-08-10 15:02:24
【问题描述】:

我正在学习算法/big o,我只是对此感到好奇。

使用

 mid = (low+high)/2;

为了获得二分搜索算法的中点,通常不鼓励使用,因为可能会出现溢出错误。为什么会导致溢出错误发生,如何

 mid = low + (high-low)/2;

防止这个错误?

谢谢。

【问题讨论】:

  • 你知道什么是溢出吗? Wikipedia 可能是一个不错的起点。
  • 是的,当堆栈太满而无法分配任何数据时。
  • @Hmir 不是这样。这里的词是关于类型溢出而不是堆栈溢出。
  • 那是一种形式的溢出(栈溢出)。在您关心 integer overflow 的场景中
  • @clcto 哦,好的,我明白了,谢谢。

标签: java algorithm binary-search


【解决方案1】:

在第一种情况下,如果 low 和 high 都足够大(假设两者都等于 2^30+1 / 甚至更大/)。在第二种情况下,你不计算 (low+high),你做了一个小技巧,然后通过表达式 (high-low) 并且该表达式相对于 int 溢出要安全得多。

不过,如果您没有一个大小大于 2^30 的数组(无论如何这是一个相当大的数组),即使使用第一个表达式,我也不知道您如何会遇到 int 溢出.所以在大多数情况下我只会使用第一个而不用担心。

【讨论】:

  • 嗯?如果low = high = Integer.MAX 怎么办?这与数组的大小有什么关系?
  • @clcto 没什么特别的,同样的......你会溢出。 low 和 high 是数组索引,OP 说的是二分查找;这就是它与数组大小的关系。
【解决方案2】:

让我们假设整数的最坏情况。 如果我们从大局来看,我们确信 mid = (low + high)/2 永远不会溢出。假设 low = 2^31 - 1 和 high = 2^31 - 1(最大整数值),总计算将是 [2*(2^31-1)] / 2 = 2^31 - 1。(最大数 int 可以容纳)

但是我们计算它的方式很重要。

    1234563 -1 ) 和高 ( 2^31 -1 ) 和 BAM。 2*(2^31-1) 是溢出。它不能将其除以 2,因为它最初无法将此值存储在 int 中。
  • 如果使用 low + (high-low)/2 计算,则无法给出溢出。 这样想,低 +(高 - 低)/2 =(低 + x),其中 x =(高 - 低)/2。为了创建溢出,我们应该为双方选择大的(在我们的情况下最大的 int)数字。但是,如果我们选择最大的低,那么 x 将是最小的(因为我们在 x 中从高减去低),反之亦然。

【讨论】:

    【解决方案3】:

    每个原始数据类型都有一个最大值和最小值。当您超过该数据类型的最大值或最小值时,它会分别回绕到最小值或最大值。

    mid = (low+high)/2;
    

    在这种情况下如果low+high>MAX_VALUE 那么你会得到奇怪的结果。

    这是一个有趣的测试,你可以试试

    int high = Integer.MAX_VALUE;
    int low = 3*Integer.MAX_VALUE/4;
    int mid = (high+low)/2;
    System.out.println(mid); // -805306369 
    

    通过更改您的数学,您可以通过减去而不是相加来消除执行最大值或最小值的机会。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-14
      相关资源
      最近更新 更多