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

Which of <random>'s random number engines should one actually use in practice? std::mt19937?

本文关键字:mt19937 引擎 std 随机数 gt random lt 实践中      更新时间:2023-10-16

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

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_64而不是std::mt19937

  • 我想说pcg64xoroshiro128,因为它们看起来很受人尊敬和轻量级,但它们根本不存在于<random>

  • 我对minstd_randminstd_rand0ranlux24knuth_b等一无所知——它们一定对某事有好处吗?

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

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

  • sizeof引擎。

  • operator()的速度.

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

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

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

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

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

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

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

例如,可以,比如说,有一个mt19937ranlux24的海湾-达勒姆洗牌,或者一个带有shuffle_order_engine的自定义linear_congruential_engine。也许包裹的发动机比原来的发动机质量更好。但是,如果不对其进行测试,就很难预测新引擎的统计质量。

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

根据C++参考,default_random_engine

库实现选择的生成器是否至少相对随意、不专业和/或轻量级的使用提供可接受的引擎行为。

因此,对于轻量级使用,您无需担心任何事情,用Epoch Time (time(0))播种default_random_engine,这已经足够好了;)