我怎样才能测试CRC32C是否是一个好的"随机发电机?

时间:2018-04-16 22:49:54

标签: c math random x86-64 crc32

我最近发现_mm_crc32_ * intel内在指令可用于生成(伪)随机32位数。

#include <nmmintrin.h> /* needs CRC32C instruction from SSE4.2 instruction set extension */

uint32_t rnd = 1; /* initialize with seed != 0 */

/* period length is 4,294,967,295 = 2^32-1 */
while (1) {
#if 0 // this was faster but worse than xorshift32 (fails more tests)
    // rnd = _mm_crc32_u8(rnd, rnd >> 3);
#else // this is faster and better than xorshift32 (fails fewer tests)
    rnd = _mm_crc32_u32(rnd, rnd << 18);
#endif
    printf("%08X\n", rnd);
}

此方法与LCG一样快,并且比xorshift32快。维基百科说,由于xorshift发生器&#34;失败了一些统计测试,他们被指责为不可靠&#34;。

现在我想知道CRC32C方法是否通过了对随机数生成器进行的各种测试。我只验证了每一位,甚至是LSB,都是&#34;随机&#34;尝试使用PAQ8压缩机进行压缩(失败)。有人可以帮我做更好的测试吗?

编辑:使用建议的TestU01套件中的测试,我之前使用的方法比xorshift32差。我已经更新了上面的源代码,以防有人对使用更好的版本感兴趣。

3 个答案:

答案 0 :(得分:5)

这是一个有趣的问题。最重要的是,唯一重要的考验是&#34;这对于我正在研究的问题产生了正确的结果。你有什么希望用rng?

为了避免针对每个不同的问题回答该问题,已经设计了各种测试。例如,参见&#34; Diehard&#34;由George Marsaglia设计的测试。网络搜索&#34; marsaglia随机数生成器测试&#34;发现几个有趣的链接。

我认为Marsaglia的作品目前还有几十年的历史。从那以后,我不知道这个话题是否有更多的工作要做。我的猜测是,对于非加密目的,通过Diehard测试的rng可能就足够了。

答案 1 :(得分:3)

对于视频游戏(尤其是单人游戏)的PRNG与蒙特卡罗模拟的要求存在很大差异。小偏差可能是科学数值计算的问题,但通常不适用于游戏,特别是如果来自同一PRNG的数字以不同方式使用。

存在不同速度/质量权衡的不同PRNG存在的原因。

这个非常快,特别是如果种子/状态保留在寄存器中,在现代Intel CPU上只占用2或3个uop。如果它可以内联到一个循环中,那就太棒了。与同等速度的其他任何东西相比,它的质量可能更好。但与较大的状态只有一点点慢的东西相比,如果你关心统计质量,它可能是可悲的。

在带有BMI2的x86上,每个RNG步骤应该只需要rorx edx, eax, 3 / crc32 eax, dl。在Haswell / Skylake上,对于循环携带的依赖性,总延迟= 1 + 3个周期的2个uop。 (http://agner.org/optimize/)。对于mov edx, eax / shr edx,3 / crc32 eax, dl而言,没有BMI2的3 uops,但CPUs with zero-latency mov for GP registers: Ivybridge+ and Ryzen上只有4个周期的延迟。

在正常情况下,2个uop对周围代码的影响可以忽略不计,在这种情况下,你对每个PRNG结果做了足够的工作,使得4周期依赖关系链不是瓶颈。 (如果你的编译器在循环中存储/重新加载PRNG状态而不是将它保存在寄存器中并且在存储循环之后将存储器下沉到全局,那么大约需要9个循环,花费你2个额外的1-uop指令)。

在Ryzen上,crc32是3个uop,总延迟为3c,因此对周围代码的影响更大,但如果你对PRNG结果的影响很小,则每4个时钟瓶颈会产生相同的影响这一点。

我怀疑你可能已经对循环承载的依赖关系链瓶颈进行了基准测试,没有对真正的周围代码的影响,这些代码做了足够的工作来隐藏延迟。 (几乎所有相关的x86 CPU都是无序执行。)使RNG比xorshift128 +甚至xorshift128便宜,对大多数用例来说可能是微不足道的好处。 xorshift128 +或xorshift128 *速度快,质量非常好。

如果您想快速获得大量PRNG结果,请考虑使用SIMD xorshift128 +并行运行两个或四个生成器(在XMM或YMM向量的不同元素中)。特别是如果您可以有用地使用PRNG结果的__m256i向量。请参阅AVX/SSE version of xorshift128+以及this answer where I used it

返回整个状态作为RNG结果通常是一件坏事,因为这意味着一个值确切地告诉您下一个将的确切内容。即3后总是跟随1897987234(假数字),从不跟随3其他东西。大多数统计质量测试应该选择这一点,但对于任何给定的用例,这可能是也可能不是问题。

请注意,https://en.wikipedia.org/wiki/Xorshift表示即使是xorshift128也无法进行一些统计测试。我认为xorshift32明显更糟。 CRC32c也是基于XOR和移位(但也有伽罗瓦域(2)中的位反射和模数),所以认为质量可能相似或更好是合理的。

你说你选择的crc32(rnd, rnd>>3)会给出一个2 ^ 32的句号,这对于一个小的状态来说是最好的。 (当然rnd++达到了同一时期,所以它不是衡量质量的唯一标准。)它可能至少和an LCG一样好,但那些是被认为是高质量的,特别是如果模数是2 ^ 32(所以你可以从固定宽度的整数数学中得到它)。

答案 2 :(得分:1)

PRNG良好性的一个衡量标准是循环的长度。如果这对您的应用很重要,那么使用CRC-32不是一个好的选择,因为周期只有2 32 。一个结果是,如果您使用的样本数量多于不长的样本,则结果将重复。另一个是连续的CRC-32值之间存在相关性,其中只有一个可能的值将跟随当前值。

更好的PRNG具有指数级更长的周期,并且返回的值小于状态中的位,因此连续值不具有该相关性。

您不需要使用CRC-32C指令来加快速度。此外,您不需要设计自己的PRNG,这充满了隐藏的危险。最好把它留给专业人士。有关高质量,小型和快速随机数生成器,请参阅this work