C ++:在范围内获取整数的最快方法

Posted

技术标签:

【中文标题】C ++:在范围内获取整数的最快方法【英文标题】:C++: Quickest way to get integer within a range 【发布时间】:2015-06-18 19:50:13 【问题描述】:

我需要为大约 N=1 亿个键生成哈希键。从我的研究看来,murmur3(MurmurHash3_x86_32,参见murmur3 hash)将是最快的散列函数,具有最佳的延迟和足够小的碰撞率。我面临的问题是该函数将键返回为void *。更具体地说,模板是:

void MurmurHash3_x86_32 (const void *key, int len, uint32_t seed, void *out);

由于我的哈希表大小会小于它可以生成的最大哈希值,我需要将它放入表范围 [0, N-1] 中。最简单的解决方案似乎是使用% 运算符。但由于它的操作速度很慢,我想知道是否有更快的方法来解决这个问题。

我发现一个有趣的建议是在 *** 本身上给出的 Is there an alternative to using % (modulus) in C/C++?。它暗示“二的幂,以下作品(假设二的补码表示)”:

return i & (n-1);

我的问题是,在较新的 CPU 上,有时(或者大多数时候?),由于多路缓存行,性能会在大约 2^n,IIRC 大小时下降。 (此链接提供了有关插入的说明 Big Memory, Part 3.5: Google sparsehash!)。

目前,murmur3 的优势似乎被硬件相关问题和% 运算符的已知效率低下所抵消。由于性能是一个限制因素,我要求低延迟和更快的解决方案来满足我的要求,即使它不是 MurmurHash3_x86_32。

【问题讨论】:

不要仅仅因为它很慢就避免使用% 运算符,如果您尝试将 128 位数字放入任意大小的空间中,您将很难做得更好。你还能举一个更好的例子来说明 2^n 左右的性能下降吗? 您是否实际检查(分析)% 的成本与 murmur3 散列的成本相比较高? 我认为您误解了“大内存,第 3.5 部分”中的性能下降。它们在那里是因为表格的对数增长。如果您预先分配整个表,您将看不到这一点。 查看igoro.com/archive/gallery-of-processor-cache-effects/… 了解有关缓存相关观察的详细信息。我还没有将 % 的性能作为给定的基准。 一个% 操作的性能与计算一个哈希值的成本相比是无关紧要的。 【参考方案1】:

我面临的问题是该函数将键返回为void *

它没有。它什么也不返回 (void)。哈希结果记录在您通过最后一个参数指定(指向)的缓冲区中。对于MurmurHash3_x86_32(),将其作为指向uint32_t 的指针是最有意义的。

由于我的哈希表大小会小于它可以生成的最大哈希值,我需要将它放入表范围 [0, N-1] 中。最简单的解决方案似乎是使用 % 运算符。但由于它的操作速度很慢,我想知道是否有更快的方法来解决这个问题。

% 不仅是最简单的解决方案,而且是最常用的解决方案。 “慢”是相对的——%+ 慢,但是比一次调用 MurmurHash3_x86_32() 快很多,很多

我发现一个有趣的建议 [...] 建议 [使用二次方表大小,并通过 & 运算符计算模数]

请注意,与 SO 答案中的断言相反,实际上这完全不依赖于二进制补码表示。

我的问题是,在较新的 CPU 上,有时(或者大多数时候?),由于多路缓存行,性能会在大约 2^n,IIRC 大小时下降。 (此链接提供了有关插入大内存的说明,第 3.5 部分:Google sparsehash!)。

您链接的报告中描述的性能下降归因于重新散列,这似乎很合理。这与您要询问的操作无关。可以想象,缓存(缺乏)关联性可能会影响大型哈希表的性能,但可能不会比拥有大型哈希表的影响更大。使用哈希表所固有的内存访问模式自然会产生较差的缓存局部性。这实际上是要点

目前,murmur3 的优势似乎被硬件相关问题和 % 运算符的已知低效率所抵消。由于性能是一个限制因素,我要求为我的要求提供低延迟和更快的解决方案,即使它不是 MurmurHash3_x86_32。

你想太多了。无法有效使用 CPU 缓存只是您为使用大型哈希表所付出的代价。它与散列函数无关(只要散列函数做得好)。单个算术运算的成本,无论是 % 还是 &,与计算散列以操作 的成本相比,都不会显着,所以你使用哪一个几乎无关紧要选择。如果您希望该操作获得微小优势,请使用大小为 2 的表和 & 运算符。另一方面,这会丢弃一些您费力计算的哈希位。考虑改为选择 prime 哈希表大小和 % 运算符 - 然后所有哈希位将有助于桶选择,这可能会改善您的传播。

【讨论】:

(a) 是的,我弄错了返回类型。对不起! (b) 我现在确信 '%' 可能不会有太大的不同。 (C)。性能下降不是由于重新散列,而是由于 N 路关联缓存。 “每个内存块可以存储在缓存中 N 个特定插槽中的任何一个中。例如,在 16 路缓存中,每个内存块可以存储在 16 个不同的缓存插槽中。通常,具有相同最低索引的块订单位将共享 16 个插槽。” (igoro.com/archive/gallery-of-processor-cache-effects) 也在其他地方,比如在 Cpu Cache 上谈论 Scott Meyers 是的,在某些访问模式下,n 路关联 CPU 缓存的驱逐率高于完全关联的缓存。但是,这与您的哈希表的大小没有太大关系,特别是如果表很大,并且它可能不是您在问题中链接的 sparsehash 文章中的性能下降的原因(文章本身属性它重新散列)。使用哈希表通常会产生本质上随机的内存访问模式,这对缓存局部性不利,但因此也可以最大限度地减少不同缓存关联性的差异。

以上是关于C ++:在范围内获取整数的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

java获取随机数(java获取随机数整数)

Python - 在给定的大数范围内找到所有完美正方形的最快方法

如何获取整数到数组(从整数 i 到整数 j)。 C#

获取使用 C#/ASP.NET 创建的 Scaffold 代码的最快方法

在c ++中获取数字的百分比

使用 Wikipedia API 获取特定时间范围内阅读次数最多的文章?