4

I am using the RNG provided by C++11 and I am also toying around with OpenMP. I have assigned an engine to each thread and as a test I give the same seed to each engine. This means that I would expect both threads to yield the exact same sequence of randomly generated numbers. Here is a MWE:

#include <iostream>
#include <random>

using namespace std;


uniform_real_distribution<double> uni(0, 1);
normal_distribution<double> nor(0, 1);


int main()
{
    #pragma omp parallel
    {
        mt19937 eng(0); //GIVE EACH THREAD ITS OWN ENGINE
        vector<double> vec;

        #pragma omp for
        for(int i=0; i<5; i++)
        {
            nor(eng);
            vec.push_back(uni(eng));
        }
        #pragma omp critical
        cout << vec[0] << endl;
    }



    return 0;
}

Most often I get the output 0.857946 0.857946, but a few times I get 0.857946 0.592845. How is the latter result possible, when the two threads have identical, uncorrelated engines?!

BillyJean
  • 1,537
  • 1
  • 22
  • 39

1 Answers1

7

You have to put nor and uni inside the omp parallel region too. Like this:

#pragma omp parallel
{
    uniform_real_distribution<double> uni(0, 1);
    normal_distribution<double> nor(0, 1);
    mt19937 eng(0); //GIVE EACH THREAD ITS OWN ENGINE
    vector<double> vec;

Otherwise there will only be one copy of each, when in fact every thread needs its own copy.

Updated to add: I now see that exactly the same problem is discussed in this stackoverflow thread.

Community
  • 1
  • 1
TonyK
  • 16,761
  • 4
  • 37
  • 72
  • I don't think questions should be marked as duplicates when their answers are the same; it makes sense for one answer to work for multiple questions, but since the questions themselves are different, it doesn't make much sense to mark them as duplicates. – Kyle Strand Apr 13 '13 at 17:40
  • I see. But this solution seems very rigid, in the sense that I have to define a distribution and engine in every parallelized region of my program. Say I want to call a function inside the `for`-loop that generates the number with that engine and distribution: Then I would have to pass both the distribution *and* the engine by reference? I.e., the prototype of the function would have to read `double gen_num(uniform_real_distribution& uni, mt19937& gen)`? – BillyJean Apr 13 '13 at 18:13