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

C++: Quickest way to get integer within a range

本文关键字:方法 整数 获取 范围内 C++      更新时间:2023-10-16

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

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

由于我的哈希表大小小于它可以生成的最大哈希,我需要将其放入表范围 [0, N-1]。最简单的解决方案似乎是使用%运算符。但是众所周知,它是一个缓慢的运算符,我想知道是否有更快的方法来解决问题。

我发现的一个有趣的建议是有没有替代在C/C++中使用%(模量)的替代方案? 在StackOverflow本身上。它建议"二的幂,以下工作(假设二的补充表示)":

return i & (n-1);

我的问题是,在较新的 CPU 上,由于多路缓存行,有时(或者大多数时候?)性能在大小 2^n 左右下降,IIRC。(此链接提供了有关插入大内存的插图,第 3.5 部分:谷歌稀疏哈希!

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

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

它没有。 它不返回任何内容(void)。 哈希结果通过最后一个参数记录在您指定的缓冲区(指针)中。 对于MurmurHash3_x86_32()来说,最有意义的是指向uint32_t的指针。

由于我的哈希表大小小于它可以生成的最大哈希,我需要将其放入表范围 [0, N-1]。最简单的解决方案似乎是使用 % 运算符。但是众所周知,它是一个缓慢的运算符,我想知道是否有更快的方法来解决问题。

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

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

请注意,与 SO 答案中的断言相反,实际上这与 twos 的补码表示完全没有依赖关系。

我的问题是,在较新的 CPU 上,由于多路缓存行,有时(或者大多数时候?)性能在大小 2^n 左右下降,IIRC。(此链接提供了有关插入大内存的插图,第 3.5 部分:谷歌稀疏哈希!

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

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

你想多了。 无法有效利用 CPU 缓存只是您使用大型哈希表所付出的代价。 它不与哈希函数相关联(只要哈希函数很好地完成其工作)。 单个算术运算的成本,无论是%还是&,与计算要操作的哈希的成本相比,都不会明显,因此选择哪一个并不重要。如果您希望该操作具有微小的优势,请使用 2 次幂大小的表和 & 运算符。 另一方面,这扔掉了一些你费了这么多钱计算的哈希位。 考虑选择主要哈希表大小和%运算符 - 然后所有哈希位都将有助于存储桶选择,这可能会改善您的点差。