我试图理解如何使用C ++ 11随机数生成功能。我担心的是表现。
假设我们需要在0..k
之间生成一系列随机整数,但每一步都会k
更改。最好的方法是什么?
示例:
for (int i=0; i < n; ++i) {
int k = i; // of course this is more complicated in practice
std::uniform_int_distribution<> dist(0, k);
int random_number = dist(engine);
// do something with random number
}
<random>
标头提供的分发非常方便。但它们对用户来说是不透明的,因此我无法轻易预测它们的表现。例如,上面dist
的构造会导致多少(如果有的话)运行时开销,这一点尚不清楚。
相反,我可以使用像
这样的东西std::uniform_real_distribution<> dist(0.0, 1.0);
for (int i=0; i < n; ++i) {
int k = i; // of course this is more complicated in practice
int random_number = std::floor( (k+1)*dist(engine) );
// do something with random number
}
避免在每次迭代中构造一个新对象。
随机数通常用于性能很重要的数值模拟中。在这些情况下使用<random>
的最佳方法是什么?
请不要回答“简介”。分析是有效优化的一部分,但是对如何使用库以及该库的性能特征有很好的理解。如果答案是它依赖于标准库实现,或者唯一知道的方法是对其进行分析,那么我宁愿不使用<random>
中的分布。相反,我可以使用我自己的实现,这对我来说是透明的,并且在必要时更容易优化。
答案 0 :(得分:6)
您可以做的一件事是拥有一个永久的发布对象,这样您每次只能创建param_type
对象:
template<typename Integral>
Integral randint(Integral min, Integral max)
{
using param_type =
typename std::uniform_int_distribution<Integral>::param_type;
// only create these once (per thread)
thread_local static std::mt19937 eng {std::random_device{}()};
thread_local static std::uniform_int_distribution<Integral> dist;
// presumably a param_type is cheaper than a uniform_int_distribution
return dist(eng, param_type{min, max});
}
答案 1 :(得分:2)
为了最大限度地提高性能,首先要考虑不同的PRNG,例如 xorshift128 + 。据报道,对于64位随机数,其速度是mt19937
的两倍多;见http://xorshift.di.unimi.it/。它可以用几行代码实现。
此外,如果您不需要“完美平衡”均匀分布,并且k
远小于2^64
(可能是),我建议简单地写一下:
uint64_t temp = engine_64(); // generates 0 <= temp < 2^64
int random_number = temp % (k + 1); // crop temp to 0,...,k
但请注意,整数除法/模运算并不便宜。例如,在Intel Haswell处理器上,64位数字需要39-103个处理器周期,这可能比调用MT19937或xorshift +引擎要长得多。