【问题标题】:Magic number in boost::hash_combineboost::hash_combine 中的幻数
【发布时间】:2011-06-24 08:13:06
【问题描述】:

boost::hash_combine 模板函数采用对哈希(称为seed)和对象v 的引用。根据docs,将seedv的hash组合成

seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);

我可以看到这是确定性的。我明白为什么要使用 XOR。

我敢打赌,这个加法有助于将相似的值映射得很远,这样探测哈希表就不会崩溃,但有人能解释一下魔法常数是什么吗?

【问题讨论】:

  • 鉴于在许多计算机上整数轮换成本与移位大致相同,将表达式转换为: seed ^= hash_value(v) + 0x9e3779b9 + rotl(seed , 6) + rotr(种子, 2);

标签: c++ algorithm boost hash magic-numbers


【解决方案1】:

幻数应该是 32 个随机位,其中每个位同样可能是 0 或 1,并且位之间没有简单的相关性。找到一串这样的位的常用方法是使用无理数的二进制展开;在这种情况下,该数字是黄金比例的倒数:

phi = (1 + sqrt(5)) / 2
2^32 / phi = 0x9e3779b9

因此,“随机”包含这个数字会改变种子的每一位;正如您所说,这意味着连续值将相距甚远。包括旧种子的移位版本可确保即使 hash_value() 的值范围相当小,差异也会很快扩散到所有位。

【讨论】:

  • 酷!当数论突然变得有用时,我喜欢它:)
  • @larsmans 我喜欢你对“突然”的使用——非常合适!在 99% 的情况下,数论就像“是的,那很好……但我有真正的工作要做,抱歉”。然后,正如你所说,“突然”,数论超级有用。它不像锤子,它相当对很多事情都有用。相反,它就像一把手术刀,对少数事情非常有用。
  • @SamKellett 如果你使用正确数量的括号并得到0x9e3779b97f4a7800,效果会更好
  • 因为 Python 的浮点数精度不够,所以上面的 64 位黄金比例是不正确的。实际结果应该是0x9e3779b97f4a7c15
  • @kennytm 你不是说0x9e3779b97f4a7c16吗?我的意思是,它只有 1 折。
【解决方案2】:

看看DDJ article by Bob Jenkins from 1997。神奇常数(“黄金比例”)解释如下:

黄金比例确实是一个任意值。其目的是避免将全零映射到全零。

【讨论】:

    猜你喜欢
    • 2014-12-29
    • 2015-07-05
    • 1970-01-01
    • 2012-01-20
    • 2018-08-19
    • 2016-06-29
    • 2013-11-26
    • 1970-01-01
    相关资源
    最近更新 更多