【问题标题】:Extremely fast hash function with collisions allowed允许冲突的极快哈希函数
【发布时间】:2013-01-31 16:37:04
【问题描述】:

我的密钥是 64 位地址,输出是 1 字节数 (0-255)。允许碰撞,但发生碰撞的概率应该很低。此外,假设要插入的元素数量很少,假设不超过 255 个,以尽量减少鸽子洞效应。

地址是程序中函数的地址。

【问题讨论】:

  • 你的地址分布是怎样的?它会对答案有所帮助,它们是什么地址?
  • Talkol - 程序中函数的地址
  • 如果你的哈希值可能有 256 个,如果你想避免冲突,元素的数量应该远小于 256。有 255 个元素,碰撞会很多。
  • 目前还没有明确定义。分布是什么?什么碰撞率是可以容忍的?
  • 哈希是否应该安全地预测给定输入的输出(在同一程序的多次迭代中)?

标签: c++ c linux hash x86-64


【解决方案1】:
uint64_t addr = ...
uint8_t hash = addr & 0xFF;

我认为这符合您的所有要求。

【讨论】:

  • 这一切都取决于地址的分布,它很容易变成可怕的
  • 尝试将 255 个键散列到 256 个值在任何情况下都可能是可怕的。这似乎是最快的解决方案。
  • 地址分布不均匀,我很确定函数地址不能是奇数,可能必须能被4整除
  • 较新的 gcc 将布局函数,以便它们在 16 字节边界上对齐
  • 而且 malloc() 块在 64 位平台上几乎总是 16 字节对齐。但亚历克斯是对的,要求是“花哨的”哈希函数可能是矫枉过正的——根本不需要太多的工作就可以均匀地分布在 256 个可能的值上。然后选择一些中间位:(((long)addr)>>5) & 0xff
【解决方案2】:

我会将 2 个 LSB(最低有效字节)异或在一起,如果分布不好,则添加第三个,依此类推

这背后的基本原理如下:函数地址分布不均匀。问题通常在于较低 (lsb) 位。函数通常需要从可被 4/8/16 整除的地址开始,因此 2-4 lsb 可能毫无意义。通过与下一个字节进行异或运算,您应该可以解决大部分问题,而且速度仍然非常快。

【讨论】:

  • XORin 与较高字节实现了相同的效果,同样快,并且更简单,因为您不确定要向右移动多少位..因为较低的“好”位提供最大的变化,所以如果你不需要,你不会想把它们扔掉
【解决方案3】:

我认为函数地址很可能是对齐的(参见this question, for instance)。这似乎表明您想要跳过最低有效位,具体取决于对齐方式。

所以,也许从第 3 位开始取 8 位,即跳过最低有效 3 位(第 0 位到第 2 位):

const uint8_t hash = (address >> 3);

通过检查您的地址集,这应该是显而易见的。在十六进制中,注意最右边的数字。

【讨论】:

  • 如果函数都在同一个dso或主程序中,高位也都一样。我怀疑只有第 4-18 位很重要。
【解决方案4】:

怎么样:

uint64_t data = 0x12131212121211B12;

uint32_t d1 = (data >> 32) ^ (uint32_t)(data);
uint16_t d2 = (d1 >> 16) ^ (uint16_t)(d1);
uint8_t  d3 = (d2 >> 8) ^ (uint8_t)(d2);

return d3; 

它将 8 个字节的所有位与 3 个移位和三个异或指令组合在一起。

【讨论】:

  • 非常好 :) 但有点矫枉过正
  • 可以避免在 x86-64 或 x86 处理器上进行 16 位和 8 位算术运算,因为您不需要将宽度减小到 8 位直到最后。此外,由于前面的海报提到的函数对齐,最后一次移位可能会更好地完成更大的右移,例如 (8+3) 或 (8+4)。
猜你喜欢
  • 1970-01-01
  • 2019-03-25
  • 2019-03-17
  • 1970-01-01
  • 2014-10-02
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多