【问题标题】:How can I test if CRC32C is a "good" random generator?如何测试 CRC32C 是否是“好”随机生成器?
【发布时间】:2018-09-26 18:53:20
【问题描述】:

我最近发现 _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 生成器“未能通过一些统计测试,因此被指责为不可靠”。

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

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

【问题讨论】:

  • 什么是“好”?这些数字在哪里使用?它们是否需要被第三方不可预测?
  • 可压缩性是对 RNG 质量的一个非常弱的测试,尤其是对于任何通用压缩器。显然,流的Kolmogorov complexity 只是起始值+ CRC 算法或问题中的代码。任何知道如何生成随机数的人都可以在给定一个 32 位值的情况下生成所有未来的随机数。
  • 我感兴趣的是,在对它们进行的统计测试中,所呈现的生成器是否比 xorshift 32 更差或更好。伪随机数生成器始终是可预测的,我认为它是可预测的。
  • 我测试了移位方向、长度和 _u8 与 _u32 的各种组合。这个周期最长,与“_mm_crc32_u32(rnd, rnd
  • 这里有使用的测试的描述。基本上它着眼于随时间和范围的分布iro.umontreal.ca/~lecuyer/myftp/papers/xorshift.pdf

标签: c math random x86-64 crc32


【解决方案1】:

衡量 PRNG 好坏的一个指标是周期的长度。如果这对您的应用程序很重要,那么您使用的 CRC-32 将不是一个好的选择,因为周期只有 232。一个后果是,如果您使用的样本比这更多(这不会花费很长时间),您的结果将重复。另一个是连续的 CRC-32 值之间存在相关性,其中只有一个可能的值将跟随当前值。

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

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

【讨论】:

  • 您引用的网站中的表格具有误导性。这表明 xorshift32 比最小 PCG 慢。
  • @ChristophFeck 好的。然后让她知道。这不是我的桌子。
【解决方案2】:

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

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


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


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

2 uops 对周围代码的影响可以忽略不计,在正常情况下,您对每个 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 和 shift(但在 Galois Field(2) 中也具有位反射和模数),因此认为它的质量可能相似或更好是合理的。

您说您选择 crc32(rnd, rnd&gt;&gt;3) 给出了 2^32 的周期,这是您在这么小的状态下可以做的最好的事情。 (当然rnd++ 达到了相同的周期,所以它不是衡量质量的唯一标准。)它可能至少和an LCG 一样好,但那些被认为是高质量的,特别是如果模数是 2^32(所以你可以从固定宽度的整数数学中免费得到它)。

【讨论】:

  • 对需要的实际周期进行了很好的分析!关于您的 cmets “有理由认为它的质量可能相似或更好 [比 xorshift32]”和“与相同速度的其他任何东西相比,它可能质量更好”,这些是我希望能够验证的问题.
  • @ChristophFeck:是的,我知道我实际上并没有直接回答这个问题,我主要想发布关于吞吐量与延迟问题的帖子,以指出您的测试可能没有反映真实情况将 PRNG 用作更大程序的一部分的成本。几个额外的延迟周期将使仅 PRNG 的循环慢 1.5 倍,但如果延迟不是瓶颈,则对周围代码的影响仍然可以忽略不计。
【解决方案3】:

这是一个有趣的问题。最终,唯一重要的测试是“这个 rng 是否为我正在处理的问题产生正确的结果”。你希望用 rng 做什么?

为了避免针对每个不同的问题回答该问题,我们设计了各种测试。例如,参见 George Marsaglia 设计的“Diehard”测试。在网络上搜索“marsaglia 随机数生成器测试”会发现几个有趣的链接。

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

【讨论】:

  • TestU01 是更新的 PRNG 测试套件。据我了解,非加密 PRNG 的开发人员倾向于同时使用 Diehard 和 TestU01。对于加密 PRNG,有 NIST SP 800-22 测试套件。
  • 感谢所有回答的人。我接受了这个答案,但所有其他 cmets 也有帮助。
猜你喜欢
  • 2021-12-20
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
相关资源
最近更新 更多