calling std::generate algorithm from the STL two times on different containers produces equivalent results.
Consider I want to fill up two float arrays with random numbers between -1. and 1. :
std::array<float, 1000> x;
std::array<float, 1000> y;
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_real_distribution<float> dis(-1.f, 1.f);
auto rand = std::bind(dis, gen);
std::generate(x.begin(), x.end(), rand);
std::generate(y.begin(), y.end(), rand);
You can test it here : http://ideone.com/X712IU. Both arrays are filled up with the exact same values :
0: -0.411968, -0.411968
1: 0.55158, 0.55158
2: 0.69889, 0.69889
3: -0.901328, -0.901328
4: -0.556142, -0.556142
5: -0.798431, -0.798431
6: -0.570874, -0.570874
7: 0.928999, 0.928999
8: 0.118056, 0.118056
9: -0.655123, -0.655123
Now if I make a new generator between the generates it works ok :
std::array<float, 1000> x;
std::array<float, 1000> y;
// Generators in different scopes, OK
std::random_device rd;
{
std::mt19937_64 gen(rd());
std::uniform_real_distribution<float> dis(-1.f, 1.f);
auto rand = std::bind(dis, gen);
std::generate(x.begin(), x.end(), rand);
}
{
std::mt19937_64 gen(rd());
std::uniform_real_distribution<float> dis(-1.f, 1.f);
auto rand = std::bind(dis, gen);
std::generate(y.begin(), y.end(), rand);
}
Gives :
0: 0.391496, -0.64993
1: 0.429592, 0.835015
2: 0.00735116, 0.77657
3: -0.548355, -0.0794801
4: -0.312095, -0.119841
5: 0.931296, 0.997449
6: -0.934924, -0.832223
7: 0.432267, 0.181224
8: 0.942709, 0.165024
9: 0.315852, -0.654576
And now with the same generator using for loops, it works as well :
// Both arrays assigned in the same loop, OK
for(size_t i = 0; i < x.size(); ++i)
{
x[i] = rand();
y[i] = rand();
}
// Arrays in separated loops, OK
for(size_t i = 0; i < x.size(); ++i)
x[i] = rand();
for(size_t i = 0; i < y.size(); ++i)
y[i] = rand();
It looks like something related to std::generate, but I can't find out what would cause this behavior.
Any explanation ? Cheers
EDIT:
As pointed out by dotcavader, the issue comes simply because the generator object has been copied (both by std::bind and std::generate). Hence the generator start with the exact same internal state for both generate.
Just to complete the answer, Praetorian and Casey gave two easy solutions for this :
Using std::reference_wrapper to store a reference in the bind instead of a copy :
auto rand = std::bind(dis, std::ref(gen));
Using a lambda that returns a reference :
auto rand = [&](){ return dis(gen); };
See Question&Answers more detail:
os