Counter Based RNGs (CBRNGs).

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.

Fixed-size Array Types

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[0], ... r.v[N-1] for the uintW_t types.

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[0], ... r[N-1], or via most of the capabilities of a C++ "Container" e.g. at(), begin(), end(), size() and others. In addition, containers have incr() and 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[0].m. The r123::ARS1xm128i_R RNGs use r123array1xm128i for both ctr_type and key_type. For the AESNI RNG, ctr_type is an r123array1xm128i, but key_type is an opaque type, which must be initialized by assignment from a userkey_type (an r123array1xm128i).

A note on aliasing and type-punning

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.

C++ API

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:

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.

A value g of type G can be invoked as g(c,k), where c is a value of type G::ctr_type and k is a value of type G::key_type, and g(c,k) returns a value of type G::ctr_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 _R:

C API

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.

The _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 philox4x32_R(r,c,k) if r cannot be evaluated at compile-time.

The supported names for the C API are

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines