这里有大量平行的RNG问题,但我找不到一个解决我的变体的问题。
我正在编写一个函数,给定一个种子用基于该种子的随机数填充长数组。我目前按顺序执行此操作,但我发现RNG占用了我程序的大量运行时间。因此,我希望通过使用多个线程来加速我的功能。但我希望这对用户透明。也就是说,给定一个种子,应该得到相同的随机数序列,与函数内部使用的线程数无关。
我目前的想法是将数组划分为块(独立于线程数),并为每个块生成新的RNG,例如通过为种子+ chunk_id播种每个RNG。然后可以独立地处理块,并且哪个线程处理哪个块无关紧要。但我担心这可能会降低RNG的质量。对于像mersenne twister这样的高品质RNG来说,这是一种安全的方法吗?
为了说明,这里有一些伪代码:
function random(array, seed, blocksize=100000)
for each block of size blocksize in array
rng[block] = create_rng(seed+i)
parallel for each block in array
for each sample in block
array[sample] = call_rng(rng[block])
这应该为每个(种子,块大小)组合产生相同的值。但这是最好的方法吗?
答案 0 :(得分:1)
我使用TestU01 random number generator test suite通过构建自定义RNG来测试此方法的有效RNG质量,该RNG每隔0x1000步重新接种一个新的顺序种子:
#include <stdlib.h>
#include "ulcg.h"
#include "unif01.h"
#include "bbattery.h"
long long i=1,j=0;
unif01_Gen * gen;
unsigned long myrand()
{
if(++i&0xfff==0)
{
ugfsr_DeleteGen(gen);
gen = ugfsr_CreateMT19937_02(++j, NULL, 0);
}
return gen->GetBits(gen->param, gen->state);
}
int main()
{
unif01_Gen *gen2 = unif01_CreateExternGenBitsL("foo", myrand);
gen = ugfsr_CreateMT19937_02(1, NULL, 0);
bbattery_Crush (gen2);
return 0;
}
结果(等待40分钟完成测试后):
Test p-value
----------------------------------------------
71 LinearComp, r = 0 1 - eps1
72 LinearComp, r = 29 1 - eps1
----------------------------------------------
All other tests were passed
这些测试是相同的测试Mersenne Twister即使在正常使用时也会失败,而不是重新播种。因此,TestU01 Crush测试无法将顺序播种场景与正常使用区分开来。
我还测试了使用另一个Mersenne Twister的输出重新接种的方法,而不是使用顺序整数。结果完全一样。
虽然我没有尝试过最耗时的&#34; BigCrush&#34;测试(花费8小时),我认为可以肯定地说,通过生成具有连续种子的子RNG,MT的质量没有明显受损,如问题中所示。