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

C++11 discarding numbers in a PRNG sequence

本文关键字:数字 丢弃 PRNG C++11      更新时间:2023-10-16

我正试图使用函数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;
}

该代码的输出是

9.97185
9.32557
1.28124

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

9.97185
0.00114381
3.02333

但我原以为前两个数字是9.971851.28124,因为数字9.32557会被跳过。

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

在生成下一个结果时,分发可以多次调用生成器,因此要获得所需的输出,需要将生成器的状态提前匹配的调用次数。作为一个快速测试,如果我们安装自己的生成器来计算的调用次数

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

然后使用

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;

这在gcc 上产生以下结果

9.97185
2
9.32557
2
1.28124
2

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

9.97185
1.28124
9.99041

我不知道有什么可移植的方法来确定分发将调用生成器的次数,所以丢弃中间结果的最佳方法可能是调用dis(gen);并忽略该结果。