2

My code below is influenced by thread "Does std::mt19937 require warmup?". When executed, two vectors are generated with same content what is not what I want. I've expected different content in both vectors. What am I doing wrong and how to fix it?

Output:

0.251423
0.729274
-1.43542
0.251423
0.729274
-1.43542

Code:

#include <vector>
#include <algorithm>
#include <iostream>
#include <random>
#include <array>
#include <functional>
#include <iterator>

class functor1
{
public:
  functor1()
  {
    std::random_device device;
    std::array<int, std::mt19937::state_size> seeds;
    std::generate_n(seeds.data(), seeds.size(), std::ref(device));
    std::seed_seq sequence(std::begin(seeds), std::end(seeds));
    engine.seed(sequence);
  }

  double operator()()
  {
    std::normal_distribution<double> distribution(0.0, 1.0);
    return distribution(engine);
  }

private:
  std::mt19937 engine;
};

int main()
{
    functor1 f1;

    std::vector<double> v0;
    std::vector<double> v1;

    std::generate_n(std::back_inserter(v0), 3, f1);
    std::generate_n(std::back_inserter(v1), 3, f1);

    std::ostream_iterator<double> out(std::cout, "\n");

    std::copy(v0.begin(), v0.end(), out);
    std::copy(v1.begin(), v1.end(), out);
}

Thanks

Community
  • 1
  • 1
user1587451
  • 978
  • 3
  • 15
  • 30
  • 1
    Does `generate_n` take `f1` by value? Perhaps you're accidentally cloning the PRNG state. – CodesInChaos Dec 08 '14 at 19:35
  • @CodesInChaos [It does](http://en.cppreference.com/w/cpp/algorithm/generate_n) – Borgleader Dec 08 '14 at 19:37
  • @CodesInChaos Sounds like that might be the answer. See [here](http://coliru.stacked-crooked.com/a/5abb9e4698b0b34b). –  Dec 08 '14 at 19:41
  • @remyabel I don't know enough C++ to write a proper answer. – CodesInChaos Dec 08 '14 at 19:44
  • See http://stackoverflow.com/questions/18880654/why-do-i-get-same-sequence-for-everyrun-with-stdrandom-device-with-mingw-gcc4 it is possible that random_device is giving you values with a constant seed, so your seeds are being generated in a constant way, so the engine's seeds are always the same, so the output vector is all the same...turtles all the way down. – IdeaHat Dec 08 '14 at 19:45
  • 2
    @CodesInChaos The only change the OP needs to make is adding [`std::ref`](http://en.cppreference.com/w/cpp/utility/functional/ref). i.e., `std::generate_n(std::back_inserter(v0), 3, std::ref(f1));` –  Dec 08 '14 at 19:46
  • Dudes, why don't you make it an answer instead of a comment? – wilx Dec 08 '14 at 19:48
  • @VáclavZeman Fastest gun in the west, dude. –  Dec 08 '14 at 19:50

1 Answers1

7

This is because f1 is copied into generate_n() function invocation. Use std::ref(f1) instead and it will return different results for v0 and v1:

std::generate_n(std::back_inserter(v0), 3, std::ref(f1));
std::generate_n(std::back_inserter(v1), 3, std::ref(f1));
wilx
  • 17,697
  • 6
  • 59
  • 114