散列码计算为什么要乘以并忽略溢出位?

时间:2011-02-10 00:54:16

标签: algorithm hashcode

这个问题并不是关于为什么人们相乘,这是相当明显的 - 关于分配。

Why use a prime number in hashCode?

但更重要的是,乘法的一个属性变得越来越重要,哈希码计算公式中包含的因子就越多。

一个简单的计算显然可能会溢出,但这并不重要。

a * 31 + b

当公式中包含许多项目时,就会出现真正的问题。

((a * 31) + b) * 31 ... 6n.

一旦包含超过5或6个项,第一项的值就会丢失,因为当哈希码值达到包括5+项时,它的位已经溢出。使用这个系统,只有最后5个左右的术语才是最终价值的重要贡献者。

31 ^ 7 > Integer.MAX_VALUE

那么为什么大多数计算都不会滚动溢出回来的位和xor w /结果的低位。我很欣赏这需要一些小问题,并且必须使用long(64位)进行计算,因此前32位可以使用整数结果进行异或,但至少不会丢失任何位。

是否有任何特殊原因可以忽略溢出?如前所述,使用很长时间并不是那么昂贵。

修改

100000*31^7=            2751261411100000       0x9C641F717C560
6553600000*31^7 180306667837849600000    0xC641F717C5600000

请注意,后一个值正好比前一个值大65536倍,这也意味着它的答案大16位。请注意,整数值为 0xC641F717C5600000为0xC5600000,实际有效值从16位值丢失。

*SAMPLE A*
65536*4096*27512614111  

=7385361114638319616
=0x667E12CDF0000000
   12345678
=0xF0000000

*SAMPLE B*
9*65536*4096*27512614111

=66468250031744876544
=0x9A6EA93D70000000
   12345678
=0x70000000

请注意, SAMPLE B 的最高位(正好是9x SAMPLE A )在最终的32位值中几乎绝对无差异 - 如果我将9x更改为17x然后低位将是相同的。但是,如果最高位由于溢出而没有“丢失”而xord位于低位32位,那么该值将是不同的。

3 个答案:

答案 0 :(得分:3)

这是乘以一个奇数的好处;较早的数字永远不会完全脱离整数的末尾。对于要丢失的元素,31^n需要是2的幂,而这不可能发生。例如,在您的情况下,使用31^7,您可以获得32位数的0x67E12CDF;因此,尽管有溢出,输入元素乘以该值仍然会对结果产生影响。

答案 1 :(得分:2)

  

是否有任何特殊原因可以忽略溢出?如前所述,使用很长时间并不是那么昂贵。

但几乎肯定没有收获。这种方法通常会产生良好的价值分布。

答案 2 :(得分:0)

我没有在示例中看到这一点。对我来说,它们似乎与计算哈希码的方式无关:a * 31 + b

你也许可以找到一些ab,它们会给出相同的哈希码,但是高位不同的地方。然后将高位反转到哈希码是有意义的。

或者,另一个例子是((a * 31) + b )*31 + ... + z。然后找到一些ab,...,z,其中哈希码不再依赖于a。因此a不会成为重要的贡献者。

当然,如果您按31更改65536,则很容易找到a,...,z。任何值都可以,所有a位都会掉落,a会向左移动并切断。但是,你能为31这样做吗?或者类似的,你可以将高位重新输入。但是,为什么呢?你能找到一个有帮助的案例吗?

65536的问题是,在二进制文件中它看起来像10000000000000000。所以,当你将一个数乘以它时,二进制数将再次得到那个16的零。对于二进制的3111111,这不会发生。

哦,我不是说这些例子不存在,因为它们确实存在(毕竟它只是一个哈希)。但是,你找不到很多或类似的例子。