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

发布于 2024-07-30 18:43:07 字数 988 浏览 10 评论 0原文

我有一组大约 100 个数字,我希望对这组数字执行 MC 模拟,基本思想是我完全随机化该组,对前大约 20 个值进行一些比较/检查,存储结果并重复。

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

目前,我正在使用 George Marsaglia 的乘法进位算法,该算法在 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 个值,只不过这似乎是一种确保不发生碰撞的优化方法。 这会提供良好的随机输出吗? 它的速度相当快。

I have a set of numbers ~100, I wish to perform MC simulation on this set, the basic idea is I fully randomize the set, do some comparison/checks on the first ~20 values, store the result and repeat.

Now the actual comparison/check algorithm is extremely fast it actually completes in about 50 CPU cycles. With this in mind, and in order to optimize these simulations I need to generate the random sets as fast as possible.

Currently I'm using a Multiply With Carry algorithm by George Marsaglia which provides me with a random integer in 17 CPU cycles, quite fast. However, using the Fisher-Yates shuffling algorithm I have to generate 100 random integers, ~1700 CPU cycles. This overshadows my comparison time by a long ways.

So my question is are there other well known/robust techniques for doing this type of MC simulation, where I can avoid the long random set generation time?

I thought about just randomly choosing 20 values from the set, but I would then have to do collision checks to ensure that 20 unique entries were chosen.

Update:

Thanks for the responses. I have another question with regards to a method I just came up with after my post. The question is, will this provide a robust truly (assuming the RNG is good) random output. Basically my method is to set up an array of integer values the same length as my input array, set every value to zero. Now I begin randomly choosing 20 values from the input set like so:

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.
    }
}

Basically what I mentioned above, choosing 20 values at random, except it seems like a somewhat optimized way of ensuring no collisions. Will this provide good random output? Its quite fast.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南汐寒笙箫 2024-08-06 18:43:07

如果您只使用随机数组中的前 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);
}

If you only use the first 20 values in the randomised array, then you only need to do 20 steps of the Fisher-Yates algorithm (Knuth's version). Then 20 values have been randomised (actually at the end of the array rather than at the beginning, in the usual formulation), in the sense that the remaining 80 steps of the algorithm are guaranteed not to move them. The other 80 positions aren't fully shuffled, but who cares?

C++ code (iterators should be random-access):

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;
    }
}

On return, the values from first through to middle-1 are shuffled. Use it like this:

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);
}
玻璃人 2024-08-06 18:43:07

罗斯模拟书提出了如下建议:


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--;
}

The Ross simulation book suggests something like the following:


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--;
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文