无法在并行中生成正态分布的随机数

huangapple go评论82阅读模式
英文:

Can't reproduce normally distributed random numbers in parallel

问题

我想要使用OpenMP并行生成可重复的随机数序列。我编写了一小段代码,为每个线程创建了自己的随机数生成器,并使用不同的种子。但当我并行生成随机数时,出现了奇怪的情况。使用均匀分布时,我得到可重复的结果,但使用正态分布时,结果不同!

更具体地说,每次运行程序时,数组似乎被打乱。

我的问题是:为什么会发生这种情况?我应该如何解决这个问题?

英文:

I want to generate a reproducible sequence of random numbers in parallel with OpenMP. I wrote a small code that creates for each thread its own RNG with different seed. But when I start generating random numbers in parallel, something strange happens. With uniform distribution I get reproducible results, but with normal distribution i get different results!

More specifically, every time I run the program, the array seems to be shuffled.

My question: Why this might be happening? And how do I resolve this issue?

#include <iostream>
#include <random>
#include <omp.h>

int main() {
	std::normal_distribution<> normal(0,1);
	std::uniform_real_distribution<> uniform(0,1);
	std::mt19937 *rng = new std::mt19937[omp_get_max_threads()];
	for(int i = 0; i < omp_get_max_threads(); ++i) {
		rng[i].seed(1+i);
	}

	int N = 100;
	double* arr = new double[N];
#pragma omp parallel for
	for(int i = 0; i < N; ++i) {
		arr[i] = normal(rng[omp_get_thread_num()]);
	}
	for(int i = 0; i < N; ++i) {
		std::cout << arr[i] << std::endl;
	}

	delete[] arr;
	delete[] rng;
	return 0;
}

答案1

得分: 2

某些std::normal_distribution的实现会一次生成两个变量。它们将第二个变量存储在分布对象中,并在下次调用时返回它。多个线程访问同一正态分布可能是出现非确定性结果的原因。

std::uniform_real_distribution通常不具有任何隐藏状态,因此每次都会调用底层的比特生成器,因此不会表现出这种行为。

存在RandomNumberDistribution.reset()方法,这暗示了在线程之间共享对象可能不安全。

如评论中建议的,如果要获得确定性结果,建议编辑您的代码,以便不调用rand()。代码的编写方式和您的需求有不同的意图,导致我(以及其他帖子的作者)感到困惑。

英文:

Some implementations of std::normal_distribution generate variates two-at-a-time. They store the second variate in the distribution object and return it the next time it's called. Having multiple threads accessing the same normal distribution is the likely the reason for seeing non-deterministic results.

std::uniform_real_distribution tends not to have any hidden state and hence call the underlying bit generator every time so doesn't exhibit this behaviour.

The existence of RandomNumberDistribution.reset() method hints that it's not safe to share objects between threads.

As suggested in the comments, I'd suggest editing your code so that it doesn't call rand() if you want deterministic results. The way the code is written and what you're asking has different intents and caused me (and other posters) to get confused.

huangapple
  • 本文由 发表于 2023年7月18日 09:51:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76709069.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定