C++快速正规随机数生成器

C++ fast normal random number generator

本文关键字:随机数生成器 C++      更新时间:2023-10-16

我使用mt19937生成器生成正常随机数,如下所示:

normal_distribution<double> normalDistr(0, 1);    
mt19937 generator(123);
vector<double> randNums(1000000);
for (size_t i = 0; i != 1000000; ++i)
{
    randNums[i] = normalDistr(generator);
}

上面的代码是有效的,但是由于我在代码中生成了超过1亿个正常的随机数,所以上面的代码非常慢。

有没有一种更快的方法来生成正常的随机数?

以下是关于如何使用代码的一些背景:

  • 随机数的质量并没有那么重要
  • 数字的精度没有那么重要,doublefloat都可以
  • 正态分布总是均值=0,西格玛=1

编辑

@Dúthomhas,Andrew:

分析后,以下功能占用了50%以上的时间:

std::normal_distribution<double>::_Eval<std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433‌​253> >

最重要的是,您真的需要同时使用100000000个随机数吗?写入和随后从RAM读取所有这些数据不可避免地需要大量时间。如果你一次只需要一个随机数,你应该避免。

假设您确实需要RAM中的所有这些数字,那么您应该首先如果您真的想知道CPU时间花在哪里/损失在哪里,请对代码进行配置。

其次,您应该避免对数据进行不必要的重新分配和初始化。这最容易通过将std::vector::reserve(final_size)std::vector::push_back()结合使用来实现。

第三,您可以使用比std::mt19937更快的RNG。当数字的质量很重要时,建议使用RNG。在线文档说,滞后的斐波那契生成器(在std:: subtract_with_carry_engine中实现)很快,但它可能没有足够长的重现期——你必须检查这一点。或者,您可能希望使用std::min_stdrand(使用线性同余生成器)

std::vector<double> make_normal_random(std::size_t number,
                                       std::uint_fast32_t seed)
{
  std::normal_distribution<double> normalDistr(0,1);    
  std::min_stdrand generator(seed);
  std::vector<double> randNums;
  randNums.reserve(number);
  while(number--)
    randNums.push_back(normalDistr(generator));
  return randNums;
}

您还需要查看std::vector reserve,而不是调整大小。它可以让你在一次射击中获得所需的所有内存。我想你不需要一次完成一亿次双打吗?

如果确实是生成器导致性能下降,则使用普通的rand函数(需要成对绘制数字),转换为0,1中的浮点或双精度,然后应用Box-Muller转换。

就时间而言,这将是难以击败的,但请注意,统计特性并不比rand好。

数字配方程序gasdev可以做到这一点——你应该可以下载一份。