Python 解释这些中点算法之间的差异

Python 解释这些中点算法之间的差异,python,Python,为什么二进制搜索的中点算法使用 low + (high-low)/2 而不是 (low + high)/2 我在谷歌上搜索了这个问题,在网上找到了非常有趣的答案 下面是一个例子: 1: public static int binarySearch(int[] a, int key) { 2: int low = 0; 3: int high = a.length - 1; 4: 5: while (low <= high) { 6

为什么二进制搜索的中点算法使用

low + (high-low)/2
而不是

(low + high)/2

我在谷歌上搜索了这个问题,在网上找到了非常有趣的答案

下面是一个例子:

1:     public static int binarySearch(int[] a, int key) {
2:         int low = 0;
3:         int high = a.length - 1;
4:
5:         while (low <= high) {
6:             int mid = (low + high) / 2;
7:             int midVal = a[mid];
8:
9:             if (midVal < key)
10:                 low = mid + 1
11:             else if (midVal > key)
12:                 high = mid - 1;
13:             else
14:                 return mid; // key found
15:         }
16:         return -(low + 1);  // key not found.
17:     }
在Pearls Bentley的编程中,他说类似的行“将m设置为l和u的平均值,截断为最接近的整数。”从表面上看,这个断言可能看起来是正确的,但对于大的整型变量low和high,它都失败了。具体地说,如果低和高的总和大于最大正int值(231-1),它将失败。总和溢出为负值,当除以2时,该值保持为负值。在C语言中,这会导致数组索引超出范围,结果不可预测。在Java中,它抛出ArrayIndexOutOfBoundsException

对于长度(以元素为单位)为230或更大(约10亿个元素)的数组,此错误可能会表现出来。这在80年代是不可想象的,当时编写了Pearls编程,但现在在谷歌和其他地方很普遍。Bentley在《Pearls编程》一书中说,“虽然第一次二进制搜索于1946年发表,但直到1962年才出现第一次对n的所有值都有效的二进制搜索。”事实是,很少有正确的版本发表过,至少在主流编程语言中是如此

那么,修复该漏洞的最佳方法是什么?这里有一个方法:

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

您的问题是为python标记的,所以我将为python回答。简言之,它没有:

上面的pythonic实现使用后一种结构。正如评论中的人指出的那样。和具有任意精度的整数

在评论中,有人推测,从类C语言移植的人可能会复制该语言更可接受的结构。这是可能的。还有人评论说一个可能比另一个快;一般来说,这样的微观优化似乎难以评论

但是。。。如果它们不是整数呢

我假设这些是整数,因为对于二进制搜索,索引是整数。如果它们确实不是整数,那么在使用它们访问数组时会遇到一些问题。但与此同时,你可能会体验到不同的结果:

a = b = sys.float_info.max
print a + (a-b)/2 # prints a really big number
print (a+b)/2 # prints inf
同样地

a = b = float("inf")
print a+(a-b)/2 # prints nan
print (a+b)/2 # prints inf

后一个例子是不同的,尽管我不清楚哪一个更好。关于出现这种情况的原因,您可以查看上面链接的文章中的溢出解释。

正因为如此:溢出的可能性较小。如果指数
high
low
为正(非负),则
low+(high-low)/2不会溢出,而
(high+low)/2可以溢出。OTOH,如果值可以是正的或负的,对于足够大的不同符号的值,您可以使用
低+(高-低)/2
溢出,而使用
(低+高)/2
不会溢出。所以,仔细选择是值得的。请注意,如果您谈论的是实际的Python级代码(不是C实现代码),那么这些都不重要。Python具有任意精度的整数数学;它们都可以工作,没有溢出的风险。@ShadowRanger-虽然有无穷大的概念,但数学与itI的关系不太好,我觉得这是为C编写的,并且未经思考就移植到python中了。两个表达式给出相同的结果,而第二个表达式实际上更快。。。你的答案如何适用(我不是开玩笑,它可能适用)?@en_Knight仔细阅读了这个问题,他想解释一下中点算法。这是一个很好的解释。嗯,我确实读过这个问题,但它现在也被标记为python(东部时间上午12:10,第一);既然python对整数的精度没有限制,那么您的帖子中描述的一些原因不适用吗?Jeremy Banks在您发布答案前一小时链接到了本文。你的答案基本上是一个链接和文章的逐字引用-也许,更多的答案应该被引用,而不是我所做的编辑。另一个答案,引用较少,在你回答之前大约50分钟被删除-当然,你看不到。你确定这是个好主意吗?
a = b = float("inf")
print a+(a-b)/2 # prints nan
print (a+b)/2 # prints inf