快速平均,无需除法

发布于 2024-07-25 20:27:04 字数 305 浏览 4 评论 0 原文

我有一个二分搜索循环,它在执行路径中被多次命中。

探查器显示,搜索的除法部分(在给定搜索范围的高索引和低索引的情况下查找中间索引)实际上是搜索中成本最高的部分,大约是 4 倍。

(我认为)它不是对于有效的二分搜索找到精确的中间值至关重要,该值只是靠近中间且在任一方向上都没有偏差的值。

是否有一种比特旋转算法可以用更快的算法替换 mid = (low + high) / 2

编辑:语言是 C#,但等效的位操作在任何语言中都有效(尽管它可能没有性能优势),这就是我保留 C# 标记的原因。

I have a binary search loop which gets hit many times in the execution path.

A profiler shows that the division part of the search (finding the middle index given the high and low indices of the search range) is actually the most costly part of the search, by a factor of about 4.

(I think) it is not critical for efficient binary search to find the exact middle value, just a value near the middle which does not have bias in either direction.

Is there a bit-twiddling algorithm to replace mid = (low + high) / 2 with something much faster?

Edit: Language is C#, but the equivalent bit-operation is valid in any language (although it may be of no performance benefit), which is why I left the C# tag off.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

十六岁半 2024-08-01 20:27:04

这是平均值的位黑客版本,不会遇到溢出问题:

unsigned int average (unsigned int x, unsigned int y)
{
  return (x&y)+((x^y)>>1);
}

Here is a bit-hack version of the average that does not suffer from the overflow problem:

unsigned int average (unsigned int x, unsigned int y)
{
  return (x&y)+((x^y)>>1);
}
别理我 2024-08-01 20:27:04
int mid = (low + high) >>> 1;

请注意,使用“(low + high) / 2”进行中点计算 将无法正常工作

int mid = (low + high) >>> 1;

Be advised that using "(low + high) / 2" for midpoint calculations won't work correctly when integer overflow becomes an issue.

轮廓§ 2024-08-01 20:27:04

您可以使用位移位并​​克服可能的溢出问题:

low + ((high-low) >> 1)

但是我必须承认我希望现代编译器和解释器将除以 2(或除以任何其他 2 的常数幂)作为位移位,所以不确定它是否会真的有帮助 - 尝试一下。

You can use bit shifting and also overcome a possible overflow issue:

low + ((high-low) >> 1)

However I must admit I expect modern compilers and interpreters to do division by 2 (or division by any other constant power of 2) as bit-shifting, so not sure if it will really help - try it out.

甜扑 2024-08-01 20:27:04

为了进一步扩展尼尔斯的答案,理查德·施罗佩尔发明了这个。

http://www.inwap.com/pdp10/hbaker/hakmem/boolean .html#item23

第 23 项(Schroeppel):

(A 和 B)+(A 或 B)= A + B =(A XOR B)+ 2(A 和 B)。

(A + B)/2 = ((A XOR B) + 2(A AND B))/2
          =  (A XOR B)/2  + (A AND B)
          =  (A XOR B)>>1 + (A AND B)


avg(x,y){return((x^y)>>1)+(x&y);}

(A AND B) + (A OR B) = A + B 因为 A AND B 给出了 2 的共享(A 和 B 之间)幂的总和,< code>A OR B 给出共享的和不共享的,因此:

(A AND B) + (A OR B) = 
   (sum of shared powers of two) + 
   ((sum of shared powers of two) + (sum of unshared powers of two)) = 
     (sum of shared powers of two) + 
     ((sum of shared powers of two) + (sum of powers of two of A only) + 
     (sum of powers of two of B only)) = 
       ((sum of shared powers of two) + (sum of powers of two of A only)) + 
       ((sum of shared powers of two) + (sum of powers of two of B only)) 
= A + B. 

A XOR B 给出 A 和 B 之间不同的位的映射。因此,

A XOR B = (sum of powers of two of A only) + (sum of powers of two of B only). 

因此:

2(A AND B) + (A XOR B) = 
       ((sum of shared powers of two) + (sum of powers of two of A only)) + 
       ((sum of shared powers of two) + (sum of powers of two of B only)) 
= A + B.

To further expand on Nils' answer Richard Schroeppel invented this.

http://www.inwap.com/pdp10/hbaker/hakmem/boolean.html#item23

ITEM 23 (Schroeppel):

(A AND B) + (A OR B) = A + B = (A XOR B) + 2 (A AND B).

(A + B)/2 = ((A XOR B) + 2(A AND B))/2
          =  (A XOR B)/2  + (A AND B)
          =  (A XOR B)>>1 + (A AND B)


avg(x,y){return((x^y)>>1)+(x&y);}

(A AND B) + (A OR B) = A + B because A AND B gives the sum of the shared (between A and B) powers of two, A OR B gives both those shared and those that aren't, hence:

(A AND B) + (A OR B) = 
   (sum of shared powers of two) + 
   ((sum of shared powers of two) + (sum of unshared powers of two)) = 
     (sum of shared powers of two) + 
     ((sum of shared powers of two) + (sum of powers of two of A only) + 
     (sum of powers of two of B only)) = 
       ((sum of shared powers of two) + (sum of powers of two of A only)) + 
       ((sum of shared powers of two) + (sum of powers of two of B only)) 
= A + B. 

A XOR B gives a map of those bits that differ between A and B. Hence,

A XOR B = (sum of powers of two of A only) + (sum of powers of two of B only). 

And thus:

2(A AND B) + (A XOR B) = 
       ((sum of shared powers of two) + (sum of powers of two of A only)) + 
       ((sum of shared powers of two) + (sum of powers of two of B only)) 
= A + B.
源来凯始玺欢你 2024-08-01 20:27:04

如果我没记错的话,在某些情况下,使用数组的中间位置实际上会更慢。 解决方案是随机选择平分数组的索引。 确定数组中位数的算法同样如此。

我不记得确切的细节,但我记得在 iTunes 上的 MIT 算法系列

If I recall correctly, there are some cases where using the exact middle of the array can actually be slower. The solution is to randomize the choice of the index where you bisect the array. Equally true of the algorithm for determining the median of an array.

I can't recall the precise details, but I remember hearing in lecture 6 of the MIT algorithms series on iTunes.

但可醉心 2024-08-01 20:27:04

尝试低 + ((高 - 低) / 2))。 这应该有效,因为您只取两个数字的平均值。 如果二分搜索列表相当大,这将减少算法所花费的时间,因为高 - 低比高 + 低要小得多。

Try low + ((high - low) / 2)). This should work because you're only taking the average of two numbers. This would reduce the amount of time the algorithm is taking if the binary search list is fairly big, since high - low is much smaller than high + low.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文