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

C++ fast normal random number generator

我正在使用 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 亿个正常随机数,所以上面的代码非常慢。

有没有更快的方法生成正态随机数?

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


编辑:

@Dúthomhas,安德鲁:

分析后,以下函数占用了超过 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> >

如果确实是生成器导致性能下降那么使用普通的rand函数(需要成对绘制数字),将0、1转换为float或double然后应用 Box Muller 变换。

这在时间上很难被击败,但请注意,统计属性并不比 rand

gasdev 的数字食谱例程可以执行此操作 - 您应该可以下载一份副本。

您还需要查看 std::vector 储备而不是调整大小。它将让您一次性获得所需的所有内存。我假设您不需要一次所有 1 亿个双打?

最重要的是,你真的需要同时100,000,000个随机数吗?将所有这些数据写入 RAM 以及随后从 RAM 中读取这些数据不可避免地需要大量时间。如果您一次只需要一个随机数,则应避免这种情况。

假设您确实需要 RAM 中的所有这些数字,那么您应该首先 如果您真的想知道 CPU 时间 spent/lost.

在哪里,请分析您的代码

其次,你应该避免不必要的数据重新分配和初始化。结合使用 std::vector::reserve(final_size)std::vector::push_back().

最容易做到这一点

第三,您可以使用比 std::mt19937 更快的 RNG。当数字的质量很重要时,建议使用 RNG。 online documentation says that the lagged Fibonacci generator (implemented in std:: subtract_with_carry_engine) is fast, but it may not have a long enough recurrence period -- you must check this. Alternatively, you may want to use std::min_stdrand (which uses the linear congruential generator)

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;
}