I am working on a synthesizer that needs 16 random numbers (float, range -1.0f…+1.0f) per voice and frame. So for 16 voices this means 256 random numbers per frame.
Instead of calling Random::nextInt() 256 times, what I would like to do is use AVX intrinsics to create 8 randoms numbers at a time.
After reading some papers on random number generation, I have learnt that the topic is not trivial at all. There are lots of algorithms, and you need to know your requirements well when selecting one.
In my case, the most important requirement is that it has to be as fast as possible.
Let’s consider Random::nextInt() as implemented in JUCE
int Random::nextInt() noexcept
{
seed = (int64) (((((uint64) seed) * 0x5deece66dLL) + 11) & 0xffffffffffffLL);
return (int) (seed >> 16);
}
At a first glance this algorithm seems to have been chosen for good real time performance. But was that the only criterion? Meaning: Is there a faster algorithm?
Also: When thinking about vectorizing nextInt(), I notice that
seed = (int64) (((((uint64) seed) * 0x5deece66dLL) + 11) & 0xffffffffffffLL);
uses signed and unsigned 64 bit int types. I have not yet figured out what the exact purpose of using these types is (although I have the suspicion that this has an influence on the quality of the generated random numbers) but since I want to calculate 8 random values simultaneously I only have 8 X 32bit available.
Is there a random number generation expert out there?
Again, my questions are:
- Was the algorithm used in the juce::Random class chosen exclusively for the best real time performance or is there a better choice in my case?
- What is the purpose of the 64bit int values used in nextInt()? Can I use 32bit ints instead? What difference does it make?
Thank you very much for any reply!
P.S.: Apparently, based on this, Lehmer’s generator is the fastest random number generator out there. Wikipedia suggests the following 32bit implementation
uint32_t lcg_parkmiller(uint32_t *state)
{
const uint32_t A = 48271;
uint32_t low = (*state & 0x7fff) * A; // max: 32,767 * 48,271 = 1,581,695,857 = 0x5e46c371
uint32_t high = (*state >> 15) * A; // max: 65,535 * 48,271 = 3,163,439,985 = 0xbc8e4371
uint32_t x = low + ((high & 0xffff) << 15) + (high >> 16); // max: 0x5e46c371 + 0x7fff8000 + 0xbc8e = 0xde46ffff
x = (x & 0x7fffffff) + (x >> 31);
return *state = x;
}