C++Guns – RoboBlog

21.04.2015

Passing random generators around (functor)

Filed under: Allgemein — Tags: — Thomas @ 02:04

Consider the following problem: One has a parallelly callable function which needs a random generator for every thread. One wants to call the function several times and every time we want another random sequence. How can we implement this?

Between every function call the random generator must keep its states. So the caller of the function must own the generator objects and pass them to the function. The caller is also in responsible the initialize the random generators. One can feed them with random seeds. But i think there exist a better solutions [1]

We create an array of n random generators, initialize them with a random seed and pass them per pointer to the function.

Inside this function we need a distribution. A simple rand() % maxrand is not good. It uses only the lower bits which may not be random. With c++11 we can bind the random generator and number distribution together. This allows us the create a nice dice() object which represent our rand(). Of course, this object can be simply pass around.

Output:

Thread 0 sum 5021
Thread 0 sum 4966
Thread 3 sum 4996
Thread 3 sum 5014
Thread 1 sum 5007
Thread 2 sum 4970
Thread 1 sum 5092
Thread 2 sum 5002
Info sizeof std::function 16

Code:

// can be passed by value
int function2(std::function dice) {
  int sum = 0;
  for(int i=0; i < 1000; i++) {
    sum += dice();
  }
  return sum;
}

int function(std::minstd_rand *generator) {
  // we need random numbers from 0 to 10
  std::uniform_int_distribution distribution(0,10);

  // we bind the generator and distribution together to a new functor dice()
  // std::bind copy its arguments by value. To change the given generator state,
  // my must pass it by reference. This can be easly done with std:ref.
  // Yeah C++ can be strange.
  std::function dice = std::bind ( distribution, std::ref(*generator) );

  return function2(dice);
}

int main() {
  omp_set_num_threads(4);

  // create 4 random generatores with random seed
  std::minstd_rand seedGen;
  std::minstd_rand generators[omp_get_num_threads()];
  for(int i=0; i < omp_get_num_threads(); i++) {
    generators[i].seed(seedGen());
  }

#pragma omp parallel for
  for(int i=0; i < 8; i++) {
    const int id = omp_get_thread_num();
    // pass one generator to our function
    int sum = function(&generators[id]);

    std::cout << "Thread " << id << " sum " << sum << "\n";
  }

  std::cout << "Info sizeof std::function " << sizeof(std::function) << "\n";

  return 0;
}

[1] Tina’s Random Number Generator Library
numbercrunch.de/trng/trng.pdf

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress