简体   繁体   English

C ++ 11 std :: generate和std :: uniform_real_distribution调用两次给出奇怪的结果

[英]C++11 std::generate and std::uniform_real_distribution called two times gives strange results

calling std::generate algorithm from the STL two times on different containers produces equivalent results. 在不同的容器上两次从STL调用std :: generate算法会产生相同的结果。

Consider I want to fill up two float arrays with random numbers between -1. 考虑我想用-1之间的随机数填充两个float数组。 and 1. : 和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 . 您可以在这里进行测试: 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 : 现在,使用同一个生成器使用for循环,它也可以正常工作:

// 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. 看起来与std :: generate有关,但是我无法找出导致此行为的原因。

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). 正如dotcavader指出的那样,问题仅是因为生成器对象已被复制(都是通过std :: bind和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 : 为了完成答案,Praetorian和Casey为此提供了两个简单的解决方案:

Using std::reference_wrapper to store a reference in the bind instead of a copy : 使用std :: reference_wrapper将引用存储在绑定中而不是副本中:

auto rand = std::bind(dis, std::ref(gen));

Using a lambda that returns a reference : 使用返回参考的lambda:

auto rand = [&](){ return dis(gen); };

I believe what's happening here is that std::generate takes its generator argument by value. 我相信这里发生的是std :: generate按值接受其生成器参数。 As soon as you pass it in, it's copied. 一旦传递进来,它就会被复制。 That means what happens inside std::generate does not affect the function object you passed in. 这意味着std :: generate内部发生的事情不会影响您传入的函数对象。

So you call generate again, and you copy the same generator function object, which then starts generating with exactly the same state including (somewhere inside there) which ever seed was used to initialise the number generation. 因此,您再次调用generate,然后复制相同的生成器函数对象,然后以完全相同的状态开始生成,包括(用于在内部某处)用于初始化数字生成的种子。

If you create a DIFFERENT generator function, even with the same parameters, you must get a different random seed inside of it. 如果创建一个DIFFERENT生成器函数,即使具有相同的参数,也必须在其中获得不同的随机种子。 This is how your other methods are generating different results. 这就是您的其他方法产生不同结果的方式。 Ultimately, their generators start with a different seed. 最终,它们的生成器以不同的种子开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM