有效地将16位整数哈希到256位空间

时间:2014-01-12 22:12:58

标签: c++ algorithm hash glsl shader

更大的听起来很奇怪,但这就是我想要做的事情。我想采用整个16位整数序列,并以一种均匀映射到256位空间的方式对每个整数进行散列。

这样做的原因是我试图将16位数字空间的子集放入256位布隆过滤器中,以便进行快速成员资格测试。

我可以在每个整数上使用一些众所周知的散列函数,但我正在寻找一个非常有效的实现(只是一些指令),以便在GPU着色器程序中运行良好。我觉得哈希输入只知道只有16位的事实可以告知散列函数是以某种方式设计的,但我没有看到解决方案。

有什么想法吗?


EDITS

根据回复,我原来的问题令人困惑。对于那个很抱歉。我将尝试用更具体的例子来重述它:

我有一个来自集合S的n个数的子集S1,它在(0,2 ^ 16-1)范围内。我需要使用由单个散列函数构造的256位布隆过滤器来表示该子集S1。布隆过滤器的原因是空间考虑。我选择了一个256位布隆过滤器,因为它符合我的空间要求,并且具有足够低的误报概率。我正在寻找一个非常简单的散列函数,它可以从集合S中取一个数字,并以256位表示它,这样每个位的概率大致相等为1或0。

散列函数要求简单的原因是这个散列函数每个像素必须运行数千次,所以在任何可以修剪指令的地方都是一个胜利。

2 个答案:

答案 0 :(得分:2)

我认为提出的问题存在一些混乱。我将首先尝试澄清上面提到的任何不一致之处。

OP最初声称他正在尝试将较小的空间映射为较大的空间。如果确实如此,则不需要使用布隆过滤器算法。相反,正如上面的评论中所建议的,标识函数是设置和测试每个位所必需的唯一“散列”函数。但是,我断言这不是OP正在寻找的东西。如果是这样,那么OP必须在存储器中存储2^256位(基于如何陈述问题),以便16位整数(即2^16)的空间小于他的集合尺寸;这是一个不合理的内存使用量,而且极不可能出现这种情况。

因此,我假设问题约束如下:我们有一个256位位向量,我们要在其中映射16位整数的空间。也就是说,我们有256位可用于映射2^16可能的不同整数。因此,我们实际上并没有映射到更大的空间,而是更小的空间。类似地,它确实出现(再次,如上面的评论中所指出的)OP正在请求单个散列函数。如果是这种情况,那么对于bloom过滤器的工作方式存在明显的误解。

Bloom过滤器通常使用一组散列独立散列函数来减少误报。在没有详细介绍的情况下,bloom过滤器的每个输入都会遍历所有n哈希函数,然后针对每个函数测试位向量中的结果索引。如果测试的所有索引都设置为1,则值可能在集合中(在所有n散列函数中有适当的冲突或重叠,将发生误报)。此外,如果任何索引设置为0,则该值中的值绝对不是。考虑到这一点,重要的是要注意完全饱和的布隆过滤器没有任何好处。也就是说,对布隆过滤器的每个查询都将返回该项目在集合中。

哈希函数问题

现在,回到OP的原始问题。使用已知的哈希算法可能是最好的(因为这些算法在数学上很难编写,而“滚动自己的”通常不会很好地结束)。如果您担心效率低至时钟周期,请使用适合您的体系结构的汇编语言自行实现算法,以减少每个哈希函数的运行时间。请记住,在算法上,哈希函数应该在O(1)时间内运行,因此如果实现正确,它们不应该贡献太多开销。为了让你开始,我建议考虑修改bernstein哈希。我已经为您的具体案例编写了一个版本(主要用于示例目的):

unsigned char modified_bernstein(short key)
{
  unsigned ret = key & 0xff;
  ret = 33 *  ret ^ (key >> 8);
  return ret % 256; // Try to do some modulo math to keep it in range
}

我调整的bernstein方法通常作为输入字节数的函数运行。由于short类型是2个字节或16-bits,我已经从算法中删除了任何变量和循环,并简单地执行了一些比特来获取每个字节。最后,unsigned char可以返回[0,256)范围内的值,该值强制哈希函数在位向量中返回有效索引。

答案 1 :(得分:2)

如果你使用uint32_t乘以16位的素数(或者就任何奇数而言)p在2 ^ 31和2 ^ 32之间,那么你“可能”涂抹了结果在32位空间内相当均匀。然后,您可能希望添加另一个素数值,以防止0映射到0(您希望每个位具有01的相等概率,只有一个2 ^ 256中的输入值应该输出全零,并且由于只有2 ^ 16个输入,这意味着您不希望它们都没有输出全零。

这就是如何通过一次操作将16位扩展到32位(加上加载常量所需的任何指令)。使用四个不同的值p1 ... p4来获得256位,并使用不同的p值运行一些测试以找到好的值(即那些产生的误报率不会超过根据您编码的集合的大小并假设理想的散列函数,您对Bloom过滤器的期望是什么。例如,我很确定-1是一个糟糕的p值。

无论你看到一些相关性有多好,但是:例如,正如我所描述的那样,所有4个单独值的最低位将是相等的,这是一个相当严重的依赖。所以你可能想要更多的“混音”操作。例如,您可能会说最终输出的每个字节应该是我所描述的两个字节的XOR(而不是两个最不重要的字节!),只是为了摆脱简单的算术关系。

除非我误解了这个问题,否则这不是Bloom过滤器通常的工作方式。通常,您希望散列为每个输入生成精确固定数量的设置位,并且计算误报率的所有算法都依赖于此。这就是为什么对于256位大小的Bloom过滤器,您通常会有k 8位哈希,而不是一个256位哈希。 k通常比位滤波器的大小小一半(最佳值是滤波器中每个值的位数,时间ln(2)约为0.7)。所以通常你希望每个比特为1的概率都高达0.5。

原因是,一旦你将4个这样的256位值进行OR运算,几乎所有滤波器中的所有位都被置位(16个中的15个)。所以你已经看到很多误报了。

但是如果你已经完成了数学运算并且你对单个散列函数感到满意,那么产生可变数量的设置位平均其中一半,那么就足够了。或者数字256的重复只是巧合,因为k恰好是你选择的集合大小为32,而你实际上使用256位散列作为32个8位哈希? / p>

[编辑:您的评论澄清了这一点,但无论如何k不应该太高,总共需要256位哈希值。显然,在这种情况下,使用每个值超过16位(即少于16个值)的布隆过滤器是没有意义的,因为使用相同的空间量可以列出值,并且误报率为0。每个值16位的过滤器给出2200中1的误报率。即使在那里,最优k只有23,也就是说你应该在过滤器中为集合中的每个值设置23位。如果您希望这些集合大于16个值,那么您希望为每个元素设置更少的位,并且您将获得更高的误报率。]