C++11 丢弃 PRNG 序列中的数字

mon*_*olo 3 c++ random c++11

我正在尝试使用该函数discard来跳过随机数序列中的数字。这是我的尝试:

#include <random>
#include <iostream>

using namespace std;

int main ()
{
  unsigned seed = 1;
  uniform_real_distribution<> dis(0,10);
  mt19937 gen (seed);
  cout << dis(gen) << endl;
  //gen.discard(1); // supposed to be the same of `dis(gen)`?
  cout << dis(gen) << endl;
  cout << dis(gen) << endl;
}
Run Code Online (Sandbox Code Playgroud)

这段代码的输出是

9.97185
9.32557
1.28124
Run Code Online (Sandbox Code Playgroud)

如果我取消注释该行,gen.discard(1)我会得到

9.97185
0.00114381
3.02333
Run Code Online (Sandbox Code Playgroud)

但我预计前两个数字是9.971851.28124,因为该数字9.32557将被跳过。

:如何discard正确使用,或者有没有与我想要的效果相同的替代解决方案?我可以简单地使用dis(gen),但是还有其他方法吗?

Pra*_*ian 5

在生成下一个结果时,分布可以多次调用生成器,因此为了获得所需的输出,您需要通过匹配的调用次数来推进生成器的状态。作为一个快速测试,如果我们装备自己的生成器来计算调用次数

struct my_mt19937 : mt19937
{
    using mt19937::mt19937;
    unsigned called = 0;

    mt19937::result_type operator()()
    {
        ++called;
        return mt19937::operator()();
    }

    unsigned invocations()
    { 
        auto result = called;
        called = 0;
        return result;
    }
};
Run Code Online (Sandbox Code Playgroud)

然后用它代替

unsigned seed = 1;
uniform_real_distribution<> dis(0,10);
my_mt19937 gen (seed);

cout << dis(gen) << endl;
cout << gen.invocations() << endl;

cout << dis(gen) << endl;
cout << gen.invocations() << endl;

cout << dis(gen) << endl;
cout << gen.invocations() << endl;
Run Code Online (Sandbox Code Playgroud)

这会在 gcc 上产生以下结果

9.97185
2
9.32557
2
1.28124
2
Run Code Online (Sandbox Code Playgroud)

因此生成器被调用两次来生成每个结果。现在,如果我们将您的示例修改为 call gen.discard(2);,它会产生您期望的结果

9.97185
1.28124
9.99041
Run Code Online (Sandbox Code Playgroud)

我不知道有一种可移植的方法来确定分布调用生成器的次数,因此放弃中间结果的最佳选择是调用dis(gen);并忽略该结果。