template <class T> inline void hash_combine(std::size_t& seed,const T& v) { std::hash<T> hasher; seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); }
编辑:另一个问题只是要求魔术数字,但我想了解整个功能,不仅仅是这部分.
解决方法
它是“好”,甚至“非常好”,至少在表面上很容易.
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
我们将假设种子是哈希算法或此算法的先前结果.
^ =表示左侧的位和右侧的位都改变了结果的位.
哈希尔(v)被假定为v上的体面的哈希,但其余的是防御,以防它不是一个体面的哈希.
0x9e3779b9是一个32位值(如果size_t是64位可以扩展,可以扩展为64位),它包含半个0和半个1.它基本上是通过将特定非理性常数近似为基2固定点值来完成的0和1的随机序列.这有助于确保如果哈希值返回不正确的值,我们仍然会在输出中得到1和0的拖尾.
(种子<< 6)(种子>>>> 2)是进入种子的一点洗牌.
想象一下,0x常量丢失.想象一下,哈希算法对于传入的几乎每个v都返回常量0x01000.现在,种子的每一位都在散列的下一次迭代中分散,在此迭代期间它再次展开.
一次迭代后,种子^ =(种子<< 6)(种子>>> 2)0x00001000变为0x00041400.然后0x00859500.重复操作时,任何设置位都会在输出位上“抹去”.最终左右的位冲突,并将设置位从“偶数位置”移动到“奇数位置”.
依赖于输入种子的值的比特在种子操作的组合操作递归时,会以相对较快的速度和复杂的方式增长.添加原因带来了更多的污点. 0x常数添加了一堆伪随机位,使得无聊的散列值在组合后占据了散列空间的几个位.
由于加法(组合“狗”和“神”的散列结果不一样),它是不对称的,它处理无聊的哈希值(将字符映射到其ascii值,仅涉及到少量位).而且,这是相当快的.
较慢的哈希结合,加密强度可以在其他情况下更好.我天真地认为,将移位作为偶数和奇数位移的组合可能是一个好主意(但是可能的附加,甚至从奇数位移动位,使得更少的问题:经过3次迭代,进入孤独的种子位将相撞并添加并导致进位).
这种分析的缺点是,使哈希函数真的很糟糕只需要一个错误.指出所有的好东西都没有帮助.所以现在呢另一件事情就是它是一个很有名气的开放源代码仓库,我还没有听到有人指出为什么它是坏的.