The counter-based random number generators (CBRNGs) in the Random123 library are described in more detail in Parallel Random Numbers: As Easy as 1, 2, 3 , which was named the Best Paper at the ACM SC'11 International Conference on High Performance Computing, Networking, Storage, and Analysis. All the CBRNGs in the library conform to a consistent interface. Basically:
value = CBRNGname(counter, key)
Thus, with some care, they can be used interchangeably in applications. (Since code compiled with AES-NI instructions will result in an illegal instruction exception on processors without those instructions, Random123 provides a haveAESNI function that can be used to detect the existence of AES at run-time; user code could use it to either report an error or substitute an alternative compatible CBRNG.)
The API descriptions below are generic, but apply to all the different families of Random123 CBRNGs.
Data is passed into and back from the Random123 functions as r123arrayNxW types; these types contain fixed-size arrays of W-bit types (
uintW_t for the most part, but also a special r123m128i wrapper for the ARS and AESNI CBRNGs). The counter argument and the return value have the same type, referred to as
ctr_type in C++, and
ctr_t in C. The type of the key argument is referred to as
key_type in C++, and
key_t in C. For an r123arrayNxW,
r, the data member
r.v is an array of N elements, each of width W (each element is type
uintW_t or an r123m128i wrapper object). C programs can access these elements as
r.v[N-1] for the
In C++, these array types closely resemble the C++0x std::array<N, uintW_t> template, but do not require C++0x libraries or compiler features. C++ programs can access array elements via operator
r[N-1], or via most of the capabilities of a C++ "Container" e.g.
size() and others. In addition, containers have
incr(unsigned long long) member function that do increment-with-carry, which facilitate using r123arrays as very-long-period counters.
If the compiler environment supports it,
Random123/array.h also declares
r123array1xm128i, which contains an array of one
r123m128i, which in turn is a class wrapping a single element of
__m128i SSE type, which can be accessed as
r.v.m. The r123::ARS1xm128i RNGs use
r123array1xm128i for both
key_type. For the AESNI RNG,
ctr_type is an
key_type is an opaque type, which must be initialized by assignment from a
userkey_type (an r123array1xm128i).
It is easiest (though not necessarily fastest) to choose a CBRNG whose
ctr_type matches the width of the random data needed by the application, e.g., Philox4x32 for applications that need random data in 32-bit words. If the application's needs don't match the counter's value_type, it is tempting to use "type punning" and pointer casts to interconvert between types. Such conversions require great care and are very difficult to do safely without use of unions or memcpy. See here and here for discussions of the pitfalls related to aliasing. The C++ r123::ReinterpretCtr template is a safe way to reinterpret
CBRNG counter types. Gcc's
-Wstrict-aliasing=2 warning level will warn if strict aliasing violations are detected. If you find yourself ignoring or disabling warnings about strict aliasing, you should strongly consider adding something like gcc's
-fnostrict-aliasing option to your compiler flags.
There are four families of CBRNGs in the library:
A counter based RNG (CBRNG) with a name of the form FamilynameNxW is a type G with the three member typedefs:
MxVof the key may not be the same as the width
NxWof the ctr_type (Philox keys are half as wide as the counter, and future CBRNGs may well have different widths).
G::ukey_type uk1, uk2; // user code initializes uk1 and uk2 G::key_type k1(uk1), k2; k2 = uk2;
For most CBRNG's, i.e., any one not in the AESNI family, it is also perfectly acceptable to set the elements of a G::key_type directly from application variables. The quality of the results will not be compromised by using highly correlated or "non-random" keys.
g of type
G can be invoked as
c is a value of type
k is a value of type
g(c,k) returns a value of type
All the CBRNGs in the library work by iterating a randomization function for a specific number of rounds. Too few rounds and the CBRNG is a poor (perhaps catastrophically poor) random number generator. Too many rounds and time is wasted with little or no improvement in the randomness of the output. Each of the CBRNGs has a specific number of rounds which the authors believe is a reasonable compromise between speed and quality. In all cases, the default number of rounds includes a margin of safety above the minimum number of rounds that have passed all of the SmallCrush, Crush and BigCrush tests in the TestU01 suite.
Users may, however wish to employ a different numbers of rounds. Each of the above classes is actually a typedef of a more general class with a template parameter that specifies the number of rounds as name_rounds. The template classes all end in
A subset of the C++ interface is also directly usable by C programs. All header files may be safely included in C files. The C API to each of the supported RNGs consists of two typedefs, name_ctr_t, name_key_t, two functions name() and name_R(), and the enum name_rounds which specifies the recommended number of rounds.
_R functions are designed and implemented so that an optimizing compiler can achieve good performance when the number of rounds is a compile-time constant. It is likely that
philox4x32_R(10,c,k) will perform much better than
r cannot be evaluated at compile-time.
The supported names for the C API are