繁体   English   中英

熵和并行随机数发生器播种

[英]Entropy and parallel random number generator seeding

我有一个循环,我在某些点添加噪音; 这些后来被用作一些统计测试的基础。

涉及的数据集非常大,所以我想使用openMP将其并行化以加快速度。 当我想拥有多个PRNG时,问题出现了。 我有自己的PRNG类基于NR的模数方法(我认为是rand4),但我不确定如何正确地播种PRNG以确保适当的熵

Normalliy我会做这样的事情

prng.initTimer();

但是如果我有一个prng数组,每个工作线程一个,那么我不能简单地在每个实例上调用initTimer - 定时器可能不会改变,并且定时器关闭可能会引入相关性。

我需要防止自然关联,而不是针对恶意攻击者(这是实验数据),所以我需要有一种安全的方式来播种rng数组。

我想过简单地使用

prng[0].initTimer()
for(int i=1; i<numRNGs; i++)
     prng[i].init(prng[0].getRandNum());

然后调用我的循环,但不确定这是否会在模数方法中引入相关性。

种子PRNG不必创建独立的流。 您应该仅播种第一个实例(称为引用)并通过快速转发引用实例来初始化其余实例。 这仅在您知道每个线程将消耗多少随机数并且快速转发算法可用时才有效。

我不太了解你的rand4(谷歌搜索它,但没有具体的内容出现),但你不应该认为只通过播种就可以创建独立的流。 你可能想要使用不同的(更好的)PRNG。 看看好吧 它速度快,具有良好的统计特性,并由知名专家开发。 WELL 512和1024是最快的PRNG之一,并且都有很长的时间段。 您可以使用不同的种子初始化多个WELL实例,以便创建独立的流。 由于周期很长,您的PRNG几乎没有机会产生重叠的随机数流。

如果经常呼叫您的PRNG,请注意虚假共享。 这篇Herb Sutter的文章解释了错误共享如何破坏多核性能。 将多个PRNG打包成连续数组几乎是错误共享的完美配方。 为了避免错误共享,可以在PRNG之间添加填充或在堆/免费存储上分配PRNG。 在后一种情况下,应使用某种对齐的分配器单独分配每个RNG。 您的编译器应提供对齐的malloc的版本。 检查文档(嗯,谷歌搜索实际上比阅读手册更快)。 Visual C ++有_aligned_malloc ,GCC有memalignposix_memalign aliment值必须是CPU的缓存行大小的倍数。 通常的做法是沿128字节边界对齐。 对于便携式解决方案,您可以使用TBB的缓存对齐分配器。

我认为这取决于你的PRNG的属性。 通常的PRNG弱点是较低位的较低熵和较低n位的较低熵。 因此,我认为您应该检查您的PRNG是否有这些弱点并相应地更改您的代码。

也许某些死硬测试会提供有用的信息,但您也可以自己检查前n值及其统计属性,如总和和方差,并将它们与预期值进行比较。

例如,播种PRNG并总结PRNG的模数为11的前100个值,重复此次R次。 如果总和与预期的总和(5 * 100 * R)非常不同,那么您的PRNG会遇到上述一个或两个弱点。

什么都不知道PRNG,我觉得使用这样的东西更安全:

prng[0].initTimer();
// Throw the first 100 values away
for(int i=1; i < 100; i++)
   prng[0].getRandNum();
// Use only higher bits for seed values (assuming 32 bit size)
for(int i=1; i<numRNGs; i++)
   prng[i].init(((prng[0].getRandNum() >> 16) << 16)
               + (prng[0].getRandNum() >> 16));

但当然,这些都是关于PRNG的猜测。 有了理想的PRNG,您的方法应该可以正常工作。

如果您使用来自相同类型的PRNG的一系列数字来种子PRNG,它们将产生相同的数字序列,彼此相互偏移。 如果您希望它们生成不同的数字,您需要使用来自不同PRNG的一系列伪随机数对它们进行种子设定。

或者,如果您使用的是带有/dev/random的类Unix系统,则只需从该设备读取即可获得一系列随机数作为种子。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM