什么是播种并行伪随机数生成器的好方法?

What is a good way to seed parallel pseudo random number generators?

我写的PRNG周期为2^64。当我使用自旋锁保护它免受 4 个线程的影响时,它的运行速度比只有一个线程时慢两倍。互斥似乎更擅长让事情变慢。所以我决定每个线程都有单独的生成器,但这里的问题是当种子太接近时,同一系列的随机数会一次又一次地出现在不同的线程中。我不是 100% 确定这会对我的模拟产生多严重的影响,但我想避免使用非常紧密的种子 PRNG。

也许我原来的问题不够具体,无法获得简单的解决方案。下面我发布了我正在使用的 PRNG。它在 Diehard 或 FIPS 等统计测试中表现非常好,但我真的无法证明原因,因为我不是这方面的专家。我需要一种方法来为 4 个或更多生成器 运行 并行找到好的种子。对于 2 个种子,最差的一对种子是相同的种子,因此 2 个线程获得相同的随机数序列。最好的一对种子将产生两个没有重叠部分的序列。

我发现随着并行生成器的数量或生成的随机数的数量或两者的增加,找到 'best' 组种子变得越来越难。每个任务将至少有 4 个线程和至少十亿个随机数。

我能达到的最简单的解决方案是定期重新播种。有时我可能得到一组不好的种子,但在定期重新播种后很快就会被更好的种子所取代。

是否有适用于任何 PRNG 的通用解决方案?或者至少我当前使用的生成器可用的东西?如果有专门设计的并且非常适合并行随机数生成的 PRNG,我可能会更改我的 PRNG。

static thread_local unsigned long long n;

void seedRand(unsigned long long s)
{
  n = s;
}

unsigned genRand(void)
{
  n *= 123456789;
  n ^= n >> 3;
  n ^= n << 5;
  return n ^= n >> 7;
}

如果您可以访问加密库,那么您可以使用 AES and split up the output among your PRNGs. For example, using counter mode 和 64 位初始种子 [seed] 来加密填充的初始种子,您可以将其连接起来,直到获得 256 的明文位数:

[种子][种子][种子][种子]

并且您的初始化向量将是 [counter][seed](您需要一个唯一的初始化向量,但不一定是一个安全的初始化向量,因为没有人试图解密您的输出)。这将产生一个 256 位的输出,前 64 位作为第一个 PRNG 的种子,第二个 64 位作为第二个 PRNG 的种子,等等。

根据加密库中提供的内容,还有其他方法可以做到这一点,例如你可以 hash the initial seed, or you could produce random UUIDs 直到你有足够的位来为你的所有 PRNG 播种。

I can possibly change my PRNG, if there's one which is specifically designed and well suited for parallel random number generation

好吧,如果您愿意更改 RNG,有些生成器具有快速(跳过调用次数的对数)跳过(a.k.a 蛙跳)。

它们在设计上保证不会重叠。比如说,您的每个线程模拟需要 10^9 个 RNG 调用并且可以 运行 在 8 个线程上,然后您从单个种子开始,第一个线程跳过 0,第二个线程跳过 10^9,线程编号N 被 (N-1)* 10^9.

跳过

合理的可接受的(它是 MCNP5 fortran 代码的重新实现)在这里 https://github.com/Iwan-Zotow/LCG-PLE63,但很可能不会通过 Diehard。

有点复杂(我相信它通过了 Diehard)http://www.pcg-random.org/

两者都基于快速求幂,F. Brown 的论文,"Random Number Generation with Arbitrary Stride," Trans。是。核素。社会。 (1994 年 11 月)