假设您想<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_64
overstd::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 字节的状态。ranlux24
并ranlux48
使用大约 577 位状态,但它们很慢(它们通过保留一些并丢弃其他伪随机输出来工作)。但是,C++ 也有两个引擎可以包装另一个引擎以潜在地改善其随机性属性:
discard_block_engine
丢弃给定随机引擎的一些输出。shuffle_order_engine
实现给定随机引擎的 Bays-Durham shuffle。举例来说,这是可能的,比方说,有一个海湾-达勒姆洗牌mt19937
,ranlux24
或自定义linear_congruential_engine
用shuffle_order_engine
。或许包装好的引擎质量比原版好。但是,如果不进行测试,就很难预测新引擎的统计质量。
因此,在进行此类测试之前,它似乎mt19937
是目前 C++ 标准中最实用的引擎。但是,我知道至少有一项提议将另一个随机数引擎添加到 C++ 的未来版本中(请参阅C++ 论文 P2075)。
归档时间: |
|
查看次数: |
1160 次 |
最近记录: |