1024:(1024*1024)在大多数情况下是一个很好的哈希码; 特别是当长线分布均匀时。
由于它是公认的答案,因此我将发布此信息,以阐明我的一些评论,即长期以来它不是一个好的哈希码。
我给出的示例是这样的Point类:
public class Point {
private final long coords; //x in high-bits, y in low
public int getX() {
return (int)(coords >> 32);
}
public int getY() {
return (int)coords;
}
public int hashCode() {
return (int)((coords >> 32) ^ (coords));
}
}
它似乎是人为的,但有时您会将多个“字段”打包成一个长整型。
因此1024:(1024*1024)字段表示x的32位和y的32位。 那么为什么这是一个问题呢? 好吧,不是x和y中的每个均匀分布在它们各自的32位上。 但这在实践中不太可能。 X和Y更有可能被某个数字限制。 假设1024是2 ^ 10。 这意味着每个X和Y最多设置低10位:
00000000 00000000 000000XX XXXXXXXX 00000000 00000000 000000YY YYYYYYYY
有2 ^ 20(1024 * 1024)种可能的组合。 但是hashCode在做什么呢?
00000000 00000000 000000XX XXXXXXXX
^ 00000000 00000000 000000YY YYYYYYYY
-------------------------------------
= 00000000 00000000 000000?? ????????
最多有2 ^ 10(1024)个hashCode值,因为只有低10位可以是零以外的任何值。 哈希值与实值的比率为1024:(1024*1024)或1:1024。因此,马上就有两个数字具有相同哈希值的概率为1/1024。
现在让我们通过应用生日问题中的数学来计算发生碰撞的可能性。 令p(n)为具有n个值的至少一次碰撞的概率。 我们知道p(1025+)= 1,因为只有1024个值。
p(n) = 1 - (n! * (1024 choose n))/1024^n
这可以解决以下问题:
n: p(n)
1: 0.00000
2: 0.00098
3: 0.00293
4: 0.00585
5: 0.00973
6: 0.01457
...
38: 0.50096
...
79: 0.95444
...
148: 0.99999
只有38个项目,可能会发生碰撞。 拥有148件物品,有99.999%的机会(至少一次)碰撞。 共有148个项目,每个项目与另一个项目发生碰撞的机率为7%。 借助适当的哈希功能,了解域知识后,这些数字很容易降至0。
换句话说,了解您的领域以及实践中的情况是进行高效哈希的关键。 库函数会尽力在不了解您的域的情况下尽力而为,并且要想表现出色,通常要依靠实践中不会出现的数据分布。