这个问题并不是关于为什么人们相乘,这是相当明显的 - 关于分配。
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位,那么该值将是不同的。
答案 0 :(得分:3)
这是乘以一个奇数的好处;较早的数字永远不会完全脱离整数的末尾。对于要丢失的元素,31^n
需要是2的幂,而这不可能发生。例如,在您的情况下,使用31^7
,您可以获得32位数的0x67E12CDF
;因此,尽管有溢出,输入元素乘以该值仍然会对结果产生影响。
答案 1 :(得分:2)
是否有任何特殊原因可以忽略溢出?如前所述,使用很长时间并不是那么昂贵。
但几乎肯定没有收获。这种方法通常会产生良好的价值分布。
答案 2 :(得分:0)
我没有在示例中看到这一点。对我来说,它们似乎与计算哈希码的方式无关:a * 31 + b
。
你也许可以找到一些a
和b
,它们会给出相同的哈希码,但是高位不同的地方。然后将高位反转到哈希码是有意义的。
或者,另一个例子是((a * 31) + b )*31 + ... + z
。然后找到一些a
,b
,...,z
,其中哈希码不再依赖于a
。因此a
不会成为重要的贡献者。
当然,如果您按31
更改65536
,则很容易找到a
,...,z
。任何值都可以,所有a
位都会掉落,a
会向左移动并切断。但是,你能为31
这样做吗?或者类似的,你可以将高位重新输入。但是,为什么呢?你能找到一个有帮助的案例吗?
65536的问题是,在二进制文件中它看起来像10000000000000000
。所以,当你将一个数乘以它时,二进制数将再次得到那个16的零。对于二进制的31
,11111
,这不会发生。
哦,我不是说这些例子不存在,因为它们确实存在(毕竟它只是一个哈希)。但是,你找不到很多或类似的例子。