简体   繁体   English

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

[英]C++ fast normal random number generator

I'm using the mt19937 generator to generate normal random numbers as shown below:我正在使用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);
}

The above code works, however since I'm generating more than 100 million normal random numbers in my code, the above is very slow.上面的代码有效,但是由于我在我的代码中生成了超过 1 亿个正常随机数,所以上面的代码非常慢。

Is there a faster way to generate normal random numbers?有没有更快的方法来生成正常的随机数?

The following is some background on how the code would be used:以下是有关如何使用代码的一些背景:

  • Quality of the random numbers is not that important随机数的质量不是那么重要
  • Precision of the numbers is not that important, either double or float is OK数字的精度不是那么重要, double floatfloat都可以
  • The normal distribution always has mean = 0 and sigma = 1正态分布的均值 = 0 和 sigma = 1

EDIT :编辑

@Dúthomhas, Andrew: @Dúthomhas,安德鲁:

After profiling the following function is taking up more than 50% of the time:分析后,以下函数占用了 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> >

Most importantly, do you really need 100,000,000 random numbers simultaneously ?最重要的是,您真的需要同时处理100,000,000 个随机数吗? The writing to and subsequent reading from RAM of all these data unavoidably requires significant time.将所有这些数据写入和随后从 RAM 中读取不可避免地需要大量时间。 If you only need the random numbers one at a time, you should avoid that.如果您一次只需要一个随机数,则应避免这种情况。

Assuming that you do need all of these numbers in RAM, then you should first profile your code if you really want to know where the CPU time is spent/lost.假设您确实需要 RAM 中的所有这些数字,那么如果您真的想知道 CPU 时间在哪里花费/丢失,您应该首先分析您的代码。

Second, you should avoid unnecessary re-allocation and initialisation of the data.其次,您应该避免不必要的数据重新分配和初始化。 This is most easily done by using std::vector::reserve(final_size) in conjunction with std::vector::push_back() .这最容易通过将std::vector::reserve(final_size)std::vector::push_back()结合使用来完成。

Third, you could use a faster RNG than std::mt19937 .第三,您可以使用比std::mt19937更快的 RNG。 That RNG is recommended when the quality of the numbers is of importance.当数字的质量很重要时,建议使用 RNG。 The 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.在线文档滞后的斐波那契生成器(在std:: subtract_with_carry_engine )速度很快,但它的重复周期可能不够长——你必须检查一下。 Alternatively, you may want to use std::min_stdrand (which uses the linear congruential generator )或者,您可能想使用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;
}

You also will want to look into std::vector reserve rather than resize.您还需要查看 std::vector 保留而不是调整大小。 It will allow you get all the memory you will need in 1 shot.它将让您一次获得所需的所有内存。 I am assuming you don't need all 100 million doubles at once?我假设您一次不需要所有 1 亿个双打?

If it really is the generator that is the cause of the performance degradation then use the ordinary rand function (you need to draw numbers in pairs), transform to a float or double in 0, 1 then apply the Box Muller transformation.如果确实是生成器导致性能下降,则使用普通的rand函数(您需要成对绘制数字),转换为 0, 1 中的浮点数或双精度数,然后应用 Box Muller 转换。

That will be hard to beat in terms of time, but note that the statistical properties are no better than rand .这在时间上很难被击败,但请注意,统计属性并不比rand

A numerical recipes routine gasdev does this - you should be able to download a copy.一个数字食谱例程 gasdev 就是这样做的——你应该可以下载一个副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM