本文介绍了C ++ 11 std :: generate和std :: uniform_real_distribution调用两次给出奇怪的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在不同的容器上两次从STL调用std :: generate算法会产生相同的结果.

calling std::generate algorithm from the STL two times on different containers produces equivalent results.

考虑一下,我想用-1之间的随机数填充两个float数组.和1.:

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);

您可以在此处进行测试: http://ideone.com/X712IU .两个数组都填充有完全相同的值:

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);
}

送礼:

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

现在使用同一个生成器使用for循环,它也可以正常工作:

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();

它看起来与std :: generate有关,但是我找不到导致此行为的原因.

It looks like something related to std::generate, but I can't find out what would cause this behavior.

有什么解释吗?干杯

如dotcavader所指出的,问题之所以简单,是因为生成器对象已被复制(由std :: bind和std :: generate共同复制).因此,生成器从两个生成器的内部状态完全相同.

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.

为了完成答案,Praetorian和Casey为此提供了两个简单的解决方案:

Just to complete the answer, Praetorian and Casey gave two easy solutions for this :

使用std :: reference_wrapper将引用存储在绑定中,而不是副本中:

Using std::reference_wrapper to store a reference in the bind instead of a copy :

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

使用返回引用的lambda:

Using a lambda that returns a reference :

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

推荐答案

我相信这里发生的是std :: generate按值接受其生成器参数.传递进来后,它就会被复制.这意味着std :: generate内部发生的事情不会影响您传入的函数对象.

I believe what's happening here is that std::generate takes its generator argument by value. 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.

因此,您再次调用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.

如果创建一个DIFFERENT生成器函数,即使具有相同的参数,也必须在其中获得不同的随机种子.这就是您的其他方法产生不同结果的方式.最终,它们的生成器以不同的种子开头.

If you create a DIFFERENT generator function, even with the same parameters, you must get a different random seed inside of it. This is how your other methods are generating different results. Ultimately, their generators start with a different seed.

这篇关于C ++ 11 std :: generate和std :: uniform_real_distribution调用两次给出奇怪的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-12 15:38