除非Raymond
Hettinger(代码的作者)陷入困境,否则我们将永远无法确定;-)但是,这些东西中的“科学”通常比您期望的要少:您采用一些通用原则,一个测试套件,然后对它们进行弄乱。常量几乎是任意的,直到结果看起来“足够好”为止。
一些通用原则“显然”在这里起作用:
要获得所需的快速“位分散”,您需要乘以一个大整数。由于在许多平台上CPython的哈希结果必须适合32位,因此最好使用需要32位的整数。而且,的确
(3644798167).bit_length() == 32
。为避免系统地丢失低阶位,您需要乘以一个奇数整数。3644798167很奇怪。
更一般而言,为避免在输入哈希中增加模式,您需要乘以质数。3644798167是质数。
而且,您还需要一个乘法器,该乘法器的二进制表示形式没有明显的重复模式。
bin(3644798167) == '0b11011001001111110011010011010111'
。那真是一团糟,这是一件好事;-)
在我看来,其他常量完全是任意的。的
if h == -1: h = 590923713
部分是由于另一个原因而需要的:在内部,CPython
-1从整数值C函数获取一个返回值,表示“需要引发异常”;即,这是错误返回。因此,您将永远不会
-1在CPython中看到任何对象的哈希码。返回的值而不是
-1完全任意的-
每次只需要是 相同的 值(而不是-1)即可。
编辑:玩
我不知道雷蒙德用什么来测试。这是我将要使用的:查看一组连续整数的所有子集的哈希统计信息。这些是有问题的,因为
hash(i) == i有很多整数
i。
>>> all(hash(i) == i for i in range(1000000))True
简单地将异或散列在一起将对此类输入产生大量抵消。
因此,这里有一个小函数可以生成所有子集,另一个函数是对所有哈希码进行简单的异或运算:
def hashxor(xs): h = 0 for x in xs: h ^= hash(x) return hdef genpowerset(xs): from itertools import combinations for length in range(len(xs) + 1): for t in combinations(xs, length): yield t
然后是一个驱动程序,以及一个显示碰撞统计信息的小功能:
def show_stats(d): total = sum(d.values()) print "total", total, "unique hashes", len(d), "collisions", total - len(d)def drive(n, hasher=hashxor): from collections import defaultdict d = defaultdict(int) for t in genpowerset(range(n)): d[hasher(t)] += 1 show_stats(d)
使用简单易用的哈希器是灾难性的:
>> drive(20)total 1048576 unique hashes 32 collisions 1048544
kes!OTOH
_hash()在这种情况下使用专为冷冻食品设计的产品可以完美地完成工作:
>>> drive(20, _hash)total 1048576 unique hashes 1048576 collisions 0
然后,您可以尝试使用该工具,看看究竟有什么作用-以及没有-真正的作用
_hash()。例如,如果
h = h * 69069 + 907133923
已移除。而且我不知道为什么会有那条线。同样,如果
^ 89869747删除了内部循环中的,它将继续在这些输入上做完美的工作-
不知道为什么也是如此。初始化可以从以下方式更改:
h = 1927868237 * (n + 1)
至:
h = n
这里也没有伤害。所有这些都符合我的期望:由于已经说明的原因,至关重要的是内部循环中的乘法常数。例如,向其添加1(使用3644798168),然后它不再是质数或奇数,并且统计信息降级为:
total 1048576 unique hashes 851968 collisions 196608
仍然相当有用,但是绝对更糟。将其更改为较小的素数,例如13,更糟糕的是:
total 1048576 unique hashes 483968 collisions 564608
使用具有明显二进制模式(例如)的乘法器
0b01010101010101010101010101010101,然后再次恶化:
total 1048576 unique hashes 163104 collisions 885472
玩吧!这些东西很有趣:-)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)