在实践中应该实际使用 <random> 的哪个随机数引擎?std::mt19937?

Quu*_*one 25 c++ random c++11

假设您想<random>在实际程序中使用 C++工具(对于“实用”的某些定义——这里的约束是这个问题的一部分)。你的代码大致如下:

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,你应该使用什么类型ENGINE

  • 我以前总是说std::mt19937因为它打字很快,而且有名字识别功能。但是现在似乎每个人都在说Mersenne Twister 非常重量级且对缓存不友好,甚至没有通过其他人所做的所有统计测试。

  • 我想说,std::default_random_engine因为这是明显的“默认”。但我不知道,如果它从平台而异,而且我不知道这是否是统计学上任何好处。

  • 由于现在每个人都在 64 位平台上,我们至少应该使用std::mt19937_64overstd::mt19937吗?

  • 我想说pcg64或者xoroshiro128因为它们看起来很受人尊敬而且很轻巧,但它们根本不存在<random>

  • 我对minstd_rand, minstd_rand0, ranlux24,knuth_b等一无所知——它们肯定有什么用吗?

显然,这里有一些相互竞争的限制。

  • 发动机的强度。(<random>没有加密强的 PRNG,但是,一些标准化的 PRNG 仍然比其他的“弱”,对吧?)

  • sizeof 引擎。

  • 其速度operator()

  • 易于播种。mt19937众所周知,很难正确播种,因为它有太多要初始化的状态。

  • 库供应商之间的可移植性。如果一个供应商foo_engine产生与另一供应商不同的数字foo_engine,这对某些应用程序不利。(希望这排除了除了可能之外的任何事情default_random_engine。)

尽你所能权衡所有这些限制,你认为最终的“保持标准库内的最佳实践”答案是什么?我应该继续使用std::mt19937,还是什么?

Pet*_* O. 18

C++ Reference列出了 C++ 当前提供的所有随机引擎。然而,引擎的选择还有很多不足之处(例如,请参阅我的高质量随机生成器列表)。例如:

  • default_random_engine 是实现定义的,因此不知道引擎是否存在应用程序可能关心的统计缺陷。
  • linear_congruential_engine实现线性同余生成器。但是,除非模数是质数且非常大(至少 64 位),否则它们的质量往往很差。此外,他们不能承认比他们的模数更多的种子。
  • minstd_rand0并且minstd_rand只承认大约 2^31 个种子。knuth_b包装 aminstd_rand0并对它进行 Bays-Durham shuffle。
  • mt19937并且mt19937_64如果它们被更好地初始化(例如,通过std::seed_seq使用 的多个输出初始化 a random_device,而不仅仅是一个),则可以接受更多的种子,但它们使用大约 2500 字节的状态。
  • ranlux24ranlux48使用大约 577 位状态,但它们很慢(它们通过保留一些并丢弃其他伪随机输出来工作)。

但是,C++ 也有两个引擎可以包装另一个引擎以潜在地改善其随机性属性:

  • discard_block_engine 丢弃给定随机引擎的一些输出。
  • shuffle_order_engine 实现给定随机引擎的 Bays-Durham shuffle。

举例来说,这是可能的,比方说,有一个海湾-达勒姆洗牌mt19937ranlux24或自定义linear_congruential_engineshuffle_order_engine。或许包装好的引擎质量比原版好。但是,如果不进行测试,就很难预测新引擎的统计质量。

因此,在进行此类测试之前,它似乎mt19937是目前 C++ 标准中最实用的引擎。但是,我知道至少有一项提议将另一个随机数引擎添加到 C++ 的未来版本中(请参阅C++ 论文 P2075)。