我最近发现_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差。我已经更新了上面的源代码,以防有人对使用更好的版本感兴趣。
答案 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个周期的延迟。
在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。