我完全相信我在某处有错误或误解了某些内容,但为什么以下代码似乎没有显示出均匀分布?
func TestMD5(t *testing.T) {
n := 50000
counts := map[uint32]int{} // # of hashes per 1/nth shard
for i := 0; i < n; i++ {
hash := md5.Sum(newUUID())
result := binary.BigEndian.Uint32(hash[:4])
counts[result/uint32(n)]++
}
dupeShards := 0
dupeEntries := 0
for _, count := range counts {
if count > 1 {
dupeShards++
dupeEntries += count - 1
}
}
t.Logf("%d inputs hashed to the same %d shards as other inputs.", dupeEntries, dupeShards)
if len(counts) < n*95/100 {
t.Fatalf("%d populated shards not within 5%% of expected %d uniform distribution!", len(counts), n)
}
}
https://play.golang.org/p/05mA0Dl9GBG
-
代码说明:
==&GT;我希望50k MD5总和可以在50k分片中均匀分布,但我一直看到只有~38k的分片,并且在~10k的分片中聚集在一起:
main.go:29: 12075 inputs hashed to the same 9921 shards as other inputs.
main.go:32: 37925 populated shards not within 5% of expected 50000 uniform distribution!
我也可以用其他哈希来重复这个(例如FNV),所以我猜我在误解某些东西。谢谢你的帮助!
答案 0 :(得分:6)
这是绝对正常的行为,并没有显示MD5实现的任何偏见或不正确。
你正在做的是(非常接近)在0到49,999之间抽取50,000个随机数。当你这样做时,几乎可以肯定会重复许多数字,因此有些数字不会出现。实际上,50,000个数字应该完全不同,绝对没有重复,这是不太可能的。
你可以用一个六面骰子来测试 - 如果你扔了6次,你就不太可能得到所有六个数字,更有可能看到它们中的3,4或5个,一个,两次或三次重复。它也与所谓的birthday paradox有关。
这种现象的另一个例子是'Panini贴纸问题'。帕尼尼贴纸专辑是一本书,可以容纳600个足球贴纸,用于纪念世界杯足球赛。每个都是编号和不同的,并且它们以包的形式随机出现。你必须得到每个号码中的一个来完成专辑。假设您购买了正确数量的贴纸以填充相册。如果你能够完美地填充相册,没有任何双打或缺少贴纸,那将是非常幸运的。事实上,你必须平均购买贴纸数量的大部分,以便至少获得其中一个(如果你不与其他收藏家交换重复)。
出现的不同值0-49,999的数量和显示“聚集”的数量可以用数学方法计算。我不确定你是如何测量丛生的。但是,即使您看到的实际值会发生变化,38K填充值的值也会在一次试验中保持稳定。
实际上,预期填充值的数量是(1 - 1 / e)n,其中n是可能值的数量,e是数学常数2.718281828 ... n = 50000的答案是31606。当然,你不会总是得到这个值,但所有结果都应该在几百左右(这里是spitballing)。你在你的程序中犯了一个小错误,所以我无法破译给你~37000的相关计算。