Random123: a Library of Counter-Based Random Number Generators

The Random123 library is a collection of counter-based random number generators (CBRNGs) for CPUs (C and C++) and GPUs (CUDA and OpenCL), as described in Parallel Random Numbers: As Easy as 1, 2, 3, Salmon, Moraes, Dror & Shaw, SC11, Seattle, Washington, USA, 2011, ACM . They are intended for use in statistical applications and Monte Carlo simulation and have passed all of the rigorous SmallCrush, Crush and BigCrush tests in the extensive TestU01 suite of statistical tests for random number generators. They are not suitable for use in cryptography or security even though they are constructed using principles drawn from cryptography.

The Random123 library was written by John Salmon and Mark Moraes. It is available from http://deshawresearch.com/resources_random123.html. Please see the license for terms and conditions. Please send feedback, including bug reports, suggestions, patches, etc. to random123@deshawresearch.com.


Unlike conventional RNGs, counter-based RNGs are stateless functions (or function classes i.e. functors) whose arguments are a counter, and a key and whose return value is the same type as the counter.

value = CBRNGname(counter, key)

The returned value is a deterministic function of the key and counter, i.e. a unique (counter, key) tuple will always produce the same result. The result is highly sensitive to small changes in the inputs, so that the sequence of values produced by simply incrementing the counter (or key) is effectively indistinguishable from a sequence of samples of a uniformly distributed random variable.

CBRNGs are as fast as, or faster than conventional RNGs, much easier to parallelize, use minimal memory/cache resources, and require very little code. On modern architectures, the Random123 CBRNGs require a few cycles per byte of random data returned and return random data in convenient sizes.

The CBRNGs in the Random123 library work with counters and keys consisting of of N words, where words have a width of W bits, encapsulated in r123arrayNxW structs, or equivalently, for C++, in the ArrayNxW typedefs in the r123 namespace.

In C++, all public names (classes, structs, typedefs, etc) are in the r123 namespace. In C, the public names (functions, enums, structs, typedefs) begin either with r123 or with one of the RNG family names, e.g., threefry, philox, ars, aesni. The RNG functions themselves have names like philox4x32. C++ class names are capitalized, e.g., Threefry4x32.

The different families of Random123 generators

Several families of CBRNGs are available in this version of the library:

Installation and Testing

The Random123 library is implemented entirely in header files. Thus, there is nothing to compile before using it and nothing to link after you have #included it in your source files. Simply direct your C or C++ compiler to find the header files in the include/ directory that was unpacked from the distribution tar file and use the Random123 header files, types and functions in your application.

In addition to the include/ files which implement the library the distribution also contains an examples/ directory. Users are STRONGLY ADVISED to compile and run the tests in examples/ before using Random123 in an application (see examples/README). Do not use the library if any tests fail. (It is not a failure for a test to report that it cannot run because of missing hardware capabilities like 64bit multiply, SSE, AES-NI or compiler capabilities)



A typical C++ use case might look like:

#include <Random123/philox.h>

typedef r123::Philox4x32 RNG;
RNG rng;
RNG::ctr_type c={{}};
RNG::key_type k={{}};
k[0] = ???; // some user_supplied_seed

   c[0] = ???; // some loop-dependent application variable 
   c[1] = ???; // another loop-dependent application variable 
   RNG::ctr_type r = rng(c, k);
   // use the random values in r for some operation related to
   // this iteration on objectid

On each iteration,r contains an array of 4 32-bit random values that will not be repeated by any other call to rng as long as c and k are not reused.

In the example above, we use the r123::Philox4x32, but any of the other CBRNGs would serve equally well.


In C, the example above could be written as:

#include <Random123/philox.h>

philox4x32_ctr_t c={{}};
philox4x32_key_t k={{}};

k.v[0] = user_supplied_seed;
    c.v[0] = ???; /* some loop-dependent application variable */
    c.v[1] = ???; /* another loop-dependent application variable */
    philox4x32_ctr_t r = philox4x32(c, k);

In C, access to the contents of the counter and key is through the fixed-size array member v.

The CUDA platform

All relevant functions in the C and C++ APIs for Random123 are declared as CUDA device functions if they are included in a CUDA kernel source file and compiled with a CUDA compiler (nvcc). They can be used exactly as described/documented for regular C or C++ programs. Note that CUDA device functions and host functions share the same namespace, so it is not currently possible to use Random123 functions in both the host portion and the device portion of the same .cu source file. The Nx32 forms are faster than the Nx64 variants on current (2011) 32-bit GPU architectures.

It has been reported that Random123 uses 16 bytes of static memory per thread. This is undesirable and not intentional, but we do not have a workaround other than to suggest adjusting memory allocation accordingly.

The pi_cuda.cu and pi_cudapp.cu examples illustrate the use of CUDA.

The OpenCL platform

The functions in the Random123 C API can all be used in OpenCL kernels, just as in regular C functions. As with CUDA, the Nx32 forms are faster than the Nx64 variants on current (2011) 32-bit GPU architectures.

The pi_opencl.c and pi_opencl_kernel.ocl examples illustrate the use of OpenCL.

C++0X <random> interface

In addition to the stateless ("pure/functional") C++ API above, the Random123 package includes two C++ classes that leverage the C++0X <random> API.

The GNU Scientific Library (GSL) interface

In addition to the stateless ("pure/functional") C API above, the Random123 package includes two C adapter interfaces to the GNU Scientific Library (GSL).

Generating uniformly distributed float and double values

The CBRNGs in the library all generate uniformly distributed integers. Sometimes one needs a uniformly distributed floating point value. For such a simple transformation, the machinery of GSL or a C++1x MicroURNG may be overkill. On the other hand, the idiosyncracies of compilers, floating point constants, multiplication and division, and mismatches between the number of bits in the input and the number of mantissa bits in the ouptut can be tricky to get right. The library provides a header file, <Random123/u01.h> with a variety of static inline functions that map uniform integers of various sizes (32 and 64 bits) into floats of various sizes (floats with 24-bit mantissas and and doubles with 53-bit mantissas). The output range may be open or closed at either end.

#include <Random123/threefry.h>
#include <Random123/u01.h>

threefry4x32_ctr_t c={{}};
threefry4x32_key_t k={{}};
threefry4x32_ctr_t r;
float x, y;
double vx, vy;

k.v[0] = user_supplied_seed;
    c.v[0] = ???; /* some loop-dependent application variable */
    c.v[1] = ???; /* another loop-dependent application variable */
    r = threefry4x32(c, k);
    /* get two single precision values in the interval (0,1) */
    x = u01_open_open_32_24(r.v[0]);
    y = u01_open_open_32_24(r.v[1]);
    /* get two double precision values in the interval [0,1] */
    vx = u01_closed_closed_32_53(r.v[2]);
    vy = u01_closed_closed_32_53(r.v[3]);

Tests and Benchmarks

The examples/ directory, contains tests, examples and benchmarks.


Although we have done our best to make Random123 portable and standards conforming, it is an unfortunate fact that there is no portable code. There is only code that has been ported. We have tested the Random123 library with the following infrastructure

Others have reported success on

We welcome feedback to random123@deshawresearch.com about ports to other environments.

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines