快速生成随机集,蒙特卡罗模拟

时间:2009-08-07 21:37:01

标签: c++ random montecarlo

我有一组数字~100,我希望在这个集合上执行MC模拟,基本思路是我完全随机化集合,对前20个值做一些比较/检查,存储结果并重复。

现在实际的比较/检查算法非常快,它实际上在大约50个CPU周期内完成。考虑到这一点,为了优化这些模拟,我需要尽可能快地生成随机集。

目前我正在使用George Marsaglia的Multiply With Carry算法,它为我提供了17个CPU周期内的随机整数,非常快。但是,使用Fisher-Yates混洗算法,我必须生成100个随机整数,~1700个CPU周期。这大大超过了我的比较时间。

所以我的问题是有没有其他众所周知/强大的技术来进行这种类型的MC模拟,在那里我可以避免长的随机集生成时间?

我想过只是从集合中随机选择20个值,但我必须进行碰撞检查以确保选择了20个唯一条目。

更新

感谢您的回复。关于我在帖子之后提出的方法,我还有另外一个问题。问题是,这是否会提供真实的(假设RNG是好的)随机输出。基本上我的方法是设置一个与输入数组长度相同的整数值数组,将每个值设置为零。现在我开始从输入集中随机选择20个值,如下所示:

int pcfast[100];
memset(pcfast,0,sizeof(int)*100);
int nchosen = 0;
while (nchosen<20)
{
    int k = rand(100); //[0,100]
    if ( pcfast[k] == 0 )
    {
        pcfast[k] = 1;
        r[nchosen++] = s[k]; // r is the length 20 output, s the input set.
    }
}

基本上我上面提到过,随机选择20个值,除了它似乎是一种确保没有碰撞的优化方式。这会提供良好的随机输出吗?它很快。

2 个答案:

答案 0 :(得分:5)

如果您只使用随机数组中的前20个值,那么您只需要执行Fisher-Yates算法(Knuth版本)的20个步骤。然后,20个值被随机化(实际上在数组的末尾而不是在通常的公式中的开头),在这个意义上,算法的剩余80个步骤保证不移动它们。其他80个职位没有完全洗牌,但谁在乎?

C ++代码(迭代器应该是随机访问):

using std::swap;

template <typename Iterator, typename Rand> // you didn't specify the type
void partial_shuffle(Iterator first, Iterator middle, Iterator last, Rand rnd) {
    size_t n = last - first;
    while (first != middle) {
        size_t k = rnd(n);   // random integer from 0 to n-1
        swap(*(first+k),*first);
        --n;
        ++first;
    }
}

返回时,firstmiddle-1的值会被随机播放。像这样使用它:

int arr[100];
for (int i = 0; i < 100; ++i) arr[i] = i;
while (need_more_samples()) {
    partial_shuffle(arr, arr+20, arr+100, my_prng);
    process_sample(arr, arr+20);
}

答案 1 :(得分:4)

罗斯模拟书提出如下内容:


double return[10];
for(int i=0, n=100; i < 10; i++) {
  int x = rand(n);  //pseudocode - generate an integer on [0,n]
  return[i] = arr[x];
  arr[x] = arr[n];
  n--;
}