我有一个伪随机数生成器的实现,特别是George Marsaglia的XOR-Shift RNG。我的实现在这里:
事实证明,第一个随机样本与种子非常密切相关,如果你看一下Reinitialise(int seed)方法,这是相当明显的。这是不好的。我提出的解决方案是按如下方式混合种子位:
_x = (uint)( (seed * 2147483647)
^ ((seed << 16 | seed >> 48) * 28111)
^ ((seed << 32 | seed >> 32) * 69001)
^ ((seed << 48 | seed >> 16) * 45083));
所以我通过将种子的位与四个素数相乘并将XORing重新形成_x来显着削弱任何相关性。我还在乘法之前旋转种子的位,以确保不同幅度的位在32位值的整个值范围内混合。
四向旋转似乎在无所事事和每次可能的旋转之间取得了很好的平衡(32)。素数是“空中手指” - 足够的幅度和位结构使位混乱并将它们“扩散”到整个32位,而不管起始种子。
我应该使用更大的素数吗?是否有一个标准的方法来解决这个问题,或许有更正式的基础?我试图用最小的CPU开销来做到这一点。
由于
=== UPDATE ===
我决定使用一些质数,其中设置位更好地分布在所有32位上。结果是我可以省略移位,因为乘法实现了相同的效果(在整个32位范围内的散列位),所以我只需添加四个产品来给出最终的种子......
_x = (uint)( (seed * 1431655781)
+ (seed * 1183186591)
+ (seed * 622729787)
+ (seed * 338294347));
我可能会减少素数/倍数。两个似乎太少了(我仍然可以看到第一个样本中的模式),三个看起来很好,所以为了安全边际我做了四个。
===更新2 ===
仅供参考,上述内容减少到功能相当:
_x = seed * 3575866506U;
我最初没有发现这一点,当我这样做时,我想知道在计算的不同阶段溢出是否会导致不同的结果。我相信答案是否定的 - 两个计算总是给出相同的答案。
答案 0 :(得分:2)
据一些研究人员称,CrapWow,Crap8和Murmur3是目前市面上最好的非加密哈希算法,既快又简单,又具有统计上的优势。
有关详情,请访问Non-Cryptographic Hash Function Zoo。