The qrand project is a high quality quick random number generator with following features:
- High quality: Passes all tests in TestU01 BigCrush suite, has better statistical properties than MT19937(if not properly seeded, which is often the case)
- Quick: The overhead for random number generation is at the same order of magnitude as the time for a single function call. It's THE fastest random number generator passes TestU01 BigCrush suite, much faster than MT19937 on modern CPUs
- Reproducible: The random number generator is deterministic and reproducible
- Long state: The state of the random number generator is 128 bytes, which is also 2 cache lines on most modern CPUs, making it as fast as possible but also retaining a long enough period for most applications
Qrand is not cryptographic secure. It's a high performance, high quality, reproducible random number generator for simulation and other applications.
It's intended to be used as a drop-in replacement for STL random number generators with better statistical properties and faster speed.
The qrand library is compatible with STL random number generators. It can be used as a drop-in replacement for STL random number generators.
#include <random>
#include <iostream>
#include "qrand.h"
int main(){
std::uniform_int_distribution<int> dist(0, 100);
std::uniform_real_distribution<double> distf(0.0, 1.0);
qrand rng;
for(int i = 0; i < 10; i++){
std::cout << dist(rng) << " " << distf(rng) << std::endl;
}
}
Or you can use the callable object as a drop in replacement for rand function:
#include <iostream>
#include "qrand.h"
int main(){
qrand randq;
for(int i = 0; i < 10; i++){
std::cout << randq() << " " << randq() % 100 << std::endl;
}
}
There is no global state, so it's thread safe as long as it's thread local:
void some_thread_function(){
static thread_local qrand randq;
// call randq
}
Or in OpenMP
extern qrand randq;
#pragma omp threadprivate(randq)
qrand randq;
To use the qrand library, simply include the header file qrand.h
. The
qrand uses VAES or AES-NI instructions to accelerate the random number
generation. So it need to be compiled with either -maes
or -mvaes
option.
The library utilizes the AVX2/AVX512F instructions if available. So it can
be compiled with -mavx2
or -mavx512f
option to accelerate the performance.
The easiest way to compile is to use the provided -march=native
option on
a modern x86 CPU.
The qrand library uses a AES round with 4 128 bit key to generate 512 bits random numbers. The counter is incremented by a balanced random delta each round.
! All variable is 512 bit
! += is 64 bit addition
const add, add0, add1
ct += add
buf = AES_ROUND(ct, key)
key += add0
buf = AES_ROUND(buf, key)
key += add1
buf = AES_ROUND(buf, key)
key = buf
The qrand library is tested on following platforms:
Intel Xeon E5-2650 (Sandy Bridge EP, AES-NI+SSE)
Intel Xeon E5-2670 v2 (Ivy Bridge EP, AES-NI+SSE)
Intel Xeon E5-2686 v4 (Broadwell EP, AES-NI+AVX2)
Intel Xeon Platinum 8259CL (Cascade Lake, AES-NI+AVX512F)
Intel Xeon Platinum 8375C (Ice Lake, VAES+AVX512F)
AMD EPYC 7571 (Zen/Naples, AES-NI+AVX2)
AMD EPYC 7R32 (Zen2/Rome, AES-NI+AVX2)
AMD EPYC 7R13 (Zen3/Milan, VAES+AVX2)
Apple M1 (Rosetta 2/GCC, AES-NI+SSE)