实际上,一个<random>随机数引擎中应该使用哪个?std :: mt19937?


21

假设您想<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);
}

我的问题是,您应该使用哪种类型ENGINE

  • 我以前经常说std::mt19937,是因为它可以快速键入并具有名称识别功能。但是这些天来,似乎每个人都在说 Mersenne Twister非常重且对缓存不友好,甚至没有通过其他人所做的所有统计测试。

  • 我想说,std::default_random_engine因为这是显而易见的“默认值”。但是我不知道它在平台之间是否有所不同,并且我也不知道它在统计上是否有好处。

  • 既然如今每个人都在64位平台上,我们至少应该使用std::mt19937_64over std::mt19937吗?

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

  • 我不知道什么minstd_randminstd_rand0ranlux24knuth_b,等-当然,他们一定是好东西?

显然,这里存在一些竞争约束。

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

  • sizeof 引擎。

  • 其速度operator()

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

  • 库供应商之间的可移植性。如果一个供应商提供的foo_engine编号与另一供应商提供的编号不同foo_engine,则对某些应用程序不利。(希望这不排除任何可能,除非default_random_engine。)

尽可能权衡所有这些限制,您将说出最终的“最佳实践留在标准库中”的答案是什么?我应该继续使用std::mt19937还是什么?


2
到最后一点,所有标准引擎适配器都被指定为在对默认构造的适配器进行特定的连续调用时返回特定的值,因此它们应该是可移植的。
1201ProgramAlarm

Answers:


15

《 C ++参考》列出了C ++当前提供的所有随机引擎。但是,引擎的选择还有很多需要改进的地方(例如,请参阅我的高质量随机生成器列表)。例如:

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

但是,C ++还具有两个引擎,它们包装了另一个引擎以潜在地改善其随机性属性:

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

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

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


1

根据C ++参考default_random_engine

是库实现选择生成器,以便为相对随意,不熟练和/或轻量级使用提供至少可接受的引擎行为

因此,对于轻量级的应用,你不需要是任何事情担心,种子default_random_engineEpoch Time (time(0))这将是不够细;)


我认为这里的问题是可移植性。尽管默认引擎可能是运行良好的引擎,但它可能无法在其他平台上重现。
bremen_matt

@bremen_matt嗯...那么,为什么我们需要重现一个“随机”数字?
Farbod Ahmadian

2
测试。为了进行测试,您需要可复制的输入。同时,您可能希望或需要这些输入是随机的。例如,大多数机器学习算法都假设参数是随机初始化的。Ransac,CNN,DNN等。许多算法需要随机参数。
bremen_matt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.