I'm using the mt19937
generator to generate normal random numbers as shown below:
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.
Is there a faster way to generate normal random numbers?
The following is some background on how the code would be used:
double
or float
is OKEDIT:
@Dúthomhas, Andrew:
After profiling the following function is taking up more than 50% of the time:
std::normal_distribution<double>::_Eval<std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253> >
Most importantly, do you really need 100,000,000 random numbers simultaneously? The writing to and subsequent reading from RAM of all these data unavoidably requires significant time. 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.
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()
.
Third, you could use a faster RNG than std::mt19937
. That RNG is recommended when the quality of the numbers is of importance. 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. 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;
}