我有许多并行遵循随机过程的粒子。对于每个粒子,都有一个与之关联的 PRNG。 模拟必须经过多次重复才能得到平均结果。对于每次重复,应在模拟开始前为每个粒子选择一个独有的 PRNG 种子。
我第一次得到 seed = time(NULL)
作为 particle1 的种子。对于其余部分,我只是执行 particle2 = seed + 1
、particle3 = seed + 2
等,所以所有粒子最终都有不同的种子。
在每次重复时,计划是为从 time(NULL)
获得的初始种子添加一个偏移量,例如 seed = seed + all_particles_offset;
然后使用前面描述的方法为每个粒子分配不同的种子。
我的问题是这种方法是否会导致可接受的随机性质量?我不关心安全性,只关心并行运行的随机数的质量以及进程不时重新播种的事实。
顺便说一句,使用的PRNG是PCG。
最佳答案
时间不是一个好种子,因为它太容易预测了。如果您经常需要种子,它也有被重复使用的风险。为避免这种情况,通常用进程和/或线程 ID 等其他内容来置换时间。
更好的是从操作系统的随机源中获取种子,例如 /dev/random
或非阻塞版本 /dev/urandom
。这将使用环境噪音和其他来源为您提供良好的随机种子。
你可以把它们结合起来,这就是Ruby's Random#new_seed
/* This gets a seed from /dev/urandom */
fill_random_bytes(seed, sizeof(*seed));
/* This further permutes the seed with the time and pid */
gettimeofday(&tv, 0);
seed[0] ^= tv.tv_usec;
seed[1] ^= (uint32_t)tv.tv_sec;
#if SIZEOF_TIME_T > SIZEOF_INT
seed[0] ^= (uint32_t)((time_t)tv.tv_sec >> SIZEOF_INT * CHAR_BIT);
#endif
seed[2] ^= getpid() ^ (n++ << 16);
seed[3] ^= (uint32_t)(VALUE)&seed;
#if SIZEOF_VOIDP > SIZEOF_INT
seed[2] ^= (uint32_t)((VALUE)&seed >> SIZEOF_INT * CHAR_BIT);
#endif
您可以从 random.c 中提取他们的随机种子代码.
为了避免从 /dev/random
中进行如此多的读取,这可能会耗尽熵,您可以改为执行 @indiv suggested in the comments :播种 PRNG 以生成更多种子。好处是你只需要一颗好种子。缺点是它可能让您容易受到 PRNG 缺陷的影响。
这实际上是 /dev/urandom
所做的,它使用 /dev/random
的真正随机性来播种它自己的 PRNG,以确保始终有随机数。你可以从 /dev/urandom
中读取你的种子。好处是这增加了另一个 PRNG,它可以通过使用相同 PRNG 算法的输出为您的 PRNG 播种来消除任何缺陷……或者它可能会使它们变得更糟。缺点是您不知道 /dev/urandom
是如何生成这些种子的,并且它会因平台而异。
任何这些都比使用 time
或 seed +1
, seed + 2
, ...
关于c - 播种许多 PRNG,然后不得不再次播种,什么是高质量的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36946553/