Apache Commons logo Apache Commons RNG

1. Purpose

Commons RNG provides generators of "pseudo-randomness", i.e. the generators produce deterministic sequences of bytes, currently in chunks of 32 (a.k.a. int) or 64 bits (a.k.a. long), depending on the implementation.

The goal was to provide an API that is simple and unencumbered with old design decisions.

The design is clean and its rationale is explained in the code and Javadoc (as well as in the extensive discussions on the "Apache Commons" project's mailing list).

The code evolved during several months in order to accommodate the requirements gathered from the design issues identified in the org.apache.commons.math3.random package and the explicit design goal of severing ties to java.util.Random.

The library is divided into modules:

  • Client API (requires Java 6)

    This module provides the interface to be passed as argument to a procedure that needs to access to a sequence of random numbers.

  • Core (requires Java 6)

    This module contains the implementations of several generators of pseudo-random sequences of numbers. Code in this module is intended to be internal to this library and no user code should access it directly. With the advent of Java modularization, it is possible that future releases of the library will enforce access through the RandomSource factory.

  • Simple (requires Java 6)

    This module provides factory methods for creating instances of all the generators implemented in the commons-rng-core module.

  • Sampling (requires Java 6)

    This module provides implementations that generate a sequence of numbers according to some specified probability distribution, and utilities to sample from a generic collection of items. It is an example of usage of the API provided in the commons-rng-client-api module.

  • Examples

    This module provides miscellaneous complete applications that illustrate usage of the library. Please note that this module is not part of the library's API; no compatibility should be expected in successive releases of "Commons RNG".

    As of version 1.1, the following modules are provided:

    • examples-jmh: JMH benchmarking (requires Java 8)

      This module uses the JMH micro-benchmark framework in order to assess the relative performance of the generators (see tables below).

    • examples-stress: Stress testing (requires Java 8)

      This module implements a wrapper that calls external tools that can assess the quality of the generators by submitting their output to a battery of "stress tests" (see tables below).

    • examples-sampling: Probability density (requires Java 8)

      This module contains the code that generates the data used to produce the probability density plots shown in this userguide.

    • examples-jpms: JPMS integration (requires Java 9)

      This module implements a dummy application that shows how to use the artefacts (produced from the maven modules described above) as Java modules (JPMS).

    • examples-quadrature: Quadrature (requires Java 8)

      This module contains an application that estimates the number 𝞹 using quasi-Montecarlo integration.

2. Usage overview

Please refer to the generated documentation (of the appropriate module) for details on the API illustrated by the following examples.

  • Random number generator objects are instantiated through factory methods defined in RandomSource, an enum that declares all the available implementations.
    import org.apache.commons.rng.UniformRandomProvider;
    import org.apache.commons.rng.simple.RandomSource;
    UniformRandomProvider rng = RandomSource.create(RandomSource.MT);
  • A generator will return a randomly selected element from a range of possible values of some Java (primitive) type.
    boolean isOn = rng.nextBoolean(); // "true" or "false".
    int n = rng.nextInt(); // Integer.MIN_VALUE <= n <= Integer.MAX_VALUE.
    int m = rng.nextInt(max); // 0 <= m < max.
    long n = rng.nextLong(); // Long.MIN_VALUE <= n <= Long.MAX_VALUE.
    long m = rng.nextLong(max); // 0 <= m < max.
    float x = rng.nextFloat(); // 0 <= x < 1.
    double x = rng.nextDouble(); // 0 <= x < 1.
  • A generator will fill a given byte array with random values.
    byte[] a = new byte[47];
    // The elements of "a" are replaced with random values from the interval [-128, 127].
    byte[] a = new byte[47];
    // Replace 3 elements of the array (at indices 15, 16 and 17) with random values.
    rng.nextBytes(a, 15, 3);
  • In order to generate reproducible sequences, generators must be instantiated with a user-defined seed.
    UniformRandomProvider rng = RandomSource.create(RandomSource.SPLIT_MIX_64, 5776);

    If no seed is passed, a random seed is generated implicitly.

    Convenience methods are provided for explicitly generating random seeds of the various types.

    int seed = RandomSource.createInt();
    long seed = RandomSource.createLong();
    int[] seed = RandomSource.createIntArray(128); // Length of returned array is 128.
    long[] seed = RandomSource.createLongArray(128); // Length of returned array is 128.
  • Any of the following types can be passed to the create method as the "seed" argument:
    • int or Integer
    • long or Long
    • int[]
    • long[]
    • byte[]
    UniformRandomProvider rng = RandomSource.create(RandomSource.ISAAC, 5776);
    UniformRandomProvider rng = RandomSource.create(RandomSource.ISAAC, new int[] { 6, 7, 7, 5, 6, 1, 0, 2 });
    UniformRandomProvider rng = RandomSource.create(RandomSource.ISAAC, new long[] { 0x638a3fd83bc0e851L, 0x9730fd12c75ae247L });

    Note however that, upon initialization, the underlying generation algorithm

    • may not use all the information contents of the seed,
    • may use a procedure (using the given seed as input) for further filling its internal state (in order to avoid a too uniform initial state).

    In both cases, the behaviour is not standard but should not change between releases of the library (bugs notwithstanding).

    Each RNG implementation has a single "native" seed; when the seed argument passed to the create method is not of the native type, it is automatically converted. The conversion preserves the information contents but is otherwise not specified (i.e. different releases of the library may use different conversion procedures).

    Hence, if reproducibility of the generated sequences across successive releases of the library is necessary, users should ensure that they use native seeds.

    long seed = 9246234616L;
    if (!RandomSource.TWO_CMRES.isNativeSeed(seed)) {
        throw new IllegalArgumentException("Seed is not native");

    For each available implementation, the native seed type is specified in the Javadoc.

  • Whenever a random source implementation is parameterized, the custom arguments are passed after the seed.
    int seed = 96912062;
    int first = 7; // Subcycle identifier.
    int second = 4; // Subcycle identifier.
    UniformRandomProvider rng = RandomSource.create(RandomSource.TWO_CMRES_SELECT, seed, first, second);

    In the above example, valid "subcycle identifiers" are in the interval [0, 13].

  • The current state of a generator can be saved and restored later on.
    import org.apache.commons.rng.RestorableUniformRandomProvider;
    import org.apache.commons.rng.RandomProviderState;
    RestorableUniformRandomProvider rng = RandomSource.create(RandomSource.WELL_512_A);
    RandomProviderState state = rng.saveState();
    double x = rng.nextDouble();
    double y = rng.nextDouble(); // x == y.
  • The UniformRandomProvider objects returned from the create methods do not implement the java.io.Serializable interface.

    However, users can easily set up a custom serialization scheme if the random source is known at both ends of the communication channel. This would be useful namely to save the state to persistent storage, and restore it such that the sequence will continue from where it left off.

    import org.apache.commons.rng.RestorableUniformRandomProvider;
    import org.apache.commons.rng.simple.RandomSource;
    import org.apache.commons.rng.core.RandomProviderDefaultState;
    RandomSource source = RandomSource.MT_64; // Known source identifier.
    RestorableUniformRandomProvider rngOrig = RandomSource.create(source); // Original RNG instance.
    // Save and serialize state.
    RandomProviderState stateOrig = rngOrig.saveState(rngOrig);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(((RandomProviderDefaultState) stateOrig).getState());
    // Deserialize state.
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bis);
    RandomProviderState stateNew = new RandomProviderDefaultState((byte[]) ois.readObject());
    RestorableUniformRandomProvider rngNew = RandomSource.create(source); // New RNG instance from the same "source".
    // Restore original state on the new instance.
  • Generation of random deviates for various distributions.
    import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
    import org.apache.commons.rng.sampling.distribution.GaussianSampler;
    import org.apache.commons.rng.sampling.distribution.MarsagliaNormalizedGaussianSampler;
    ContinuousSampler sampler = new GaussianSampler(new MarsagliaNormalizedGaussianSampler(RandomSource.create(RandomSource.MT_64)),
                                                    45.6, 2.3);
    double random = sampler.sample();
    import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
    import org.apache.commons.rng.sampling.distribution.RejectionInversionZipfSampler;
    DiscreteSampler sampler = new RejectionInversionZipfSampler(RandomSource.create(RandomSource.ISAAC),
                                                                5, 1.2);
    int random = sampler.sample();
  • Permutation, sampling from a Collection and shuffling utilities.
    import org.apache.commons.rng.sampling.PermutationSampler;
    PermutationSampler sampler = new PermutationSampler(RandomSource.create(RandomSource.KISS),
                                                        6, 3);
    // 3 elements from a shuffling of the (0, 1, 2, 3, 4, 5) tuplet.
    int[] random = sampler.sample();
    import java.util.ArrayList;
    import org.apache.commons.rng.sampling.CollectionSampler;
    ArrayList<String> list = new ArrayList<String>();
    CollectionSampler<String> sampler = new CollectionSampler<String>(RandomSource.create(RandomSource.MWC_256),
                                                                      list, 1);
    String word = sampler.sample().get(0);

3. Library layout

The API for client code consists of classes and interfaces defined in package org.apache.commons.rng.

  • Interface UniformRandomProvider provides access to a sequence of random values uniformly distributed within some range.
  • Interfaces RestorableUniformRandomProvider and RandomProviderState provide the "save/restore" API.

The API for instantiating generators is defined in package org.apache.commons.rng.simple.

  • Enum RandomSource determines which algorithm to use for generating the sequence of random values.

The org.apache.commons.rng.simple.internal package contains classes for supporting initialization (a.k.a. "seeding") of the generators. They must not be used directly in applications, as all the necessary utilities are accessible through methods defined in RandomSource.

  • ProviderBuilder: contains methods for instantiating the concrete RNG implementations based on the source identifier; it also takes care of calling the appropriate classes for seed type conversion.
  • SeedFactory: contains factory methods for generating random seeds.
  • SeedConverter: interface for classes that transform between supported seed types.
  • Various classes that implement SeedConverter in order to transform from caller's seed to "native" seed.

The org.apache.commons.rng.core package contains the implementation of the algorithms for the generation of pseudo-random sequences. Applications should not directly import or use classes defined in this package: all generators can be instantiated through the RandomSource factory.

  • Class RandomProviderDefaultState implements the RandomProviderState interface to enable "save/restore" for all RestorableUniformRandomProvider instances created through the RandomSource factory methods.
  • BaseProvider: base class for all concrete RNG implementations; it contains higher-level algorithms nextInt(int n) and nextLong(long n) common to all implementations.
  • org.apache.commons.rng.core.util
    • NumberFactory: contains utilities for interpreting and combining the output (int or long) of the underlying source of randomness into the requested output, i.e. one of the Java primitive types supported by UniformRandomProvider.
  • org.apache.commons.rng.core.source32
    • RandomIntSource: describes an algorithm that generates randomness in 32-bits chunks (a.k.a Java int).
    • IntProvider: base class for concrete classes that implement RandomIntSource.
    • Concrete RNG algorithms that are subclasses of IntProvider.
  • org.apache.commons.rng.core.source64
    • RandomLongSource: describes an algorithm that generates randomness in 64-bits chunks (a.k.a Java long).
    • LongProvider: base class for concrete classes that implement RandomLongSource.
    • Concrete RNG algorithms that are subclasses of LongProvider.

4. Performance

This section reports performance benchmarks of the RNG implementations.

All runs were performed on a platform with the following characteristics:

  • CPU: Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
  • Java version: 1.8.0_181 (build 1.8.0_181-8u181-b13-2~deb9u1-b13)
  • JVM: OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)

The following tables indicate the performance (as measured by JMH) for generating

  • a sequence of 32-bits integers (a.k.a. Java type int)
  • a sequence of 64-bits integers (a.k.a. Java type long)
  • a sequence of 64-bits floating point numbers (a.k.a. Java type double)

The first column is the RNG identifier (see RandomSource).

In these tables, lower is better.

  • Generating int values
    RNG identifier Score (normalized to the score of RandomSource.JDK)
    SPLIT_MIX_64 0.41479
    MWC_256 0.45309
    TWO_CMRES 0.46736
    XOR_SHIFT_1024_S 0.47100
    MT_64 0.54314
    KISS 0.59604
    ISAAC 0.65440
    MT 0.70081
    WELL_512_A 0.82333
    WELL_1024_A 0.89367
    JDK 1.00000
    WELL_19937_A 1.06771
    WELL_44497_A 1.08662
    WELL_19937_C 1.13443
    WELL_44497_B 1.17291
  • Generating long values
    RNG identifier Score (normalized to the score of RandomSource.JDK)
    SPLIT_MIX_64 0.21751
    TWO_CMRES 0.25344
    XOR_SHIFT_1024_S 0.27299
    MWC_256 0.32938
    MT_64 0.36588
    KISS 0.50416
    MT 0.54819
    ISAAC 0.60151
    WELL_1024_A 0.66864
    WELL_512_A 0.69384
    JDK 1.00000
    WELL_19937_A 1.00596
    WELL_44497_A 1.05796
    WELL_19937_C 1.09265
    WELL_44497_B 1.16150
  • Generating double values
    RNG identifier Score (normalized to the score of RandomSource.JDK)
    SPLIT_MIX_64 0.27611
    TWO_CMRES 0.31356
    XOR_SHIFT_1024_S 0.33200
    MWC_256 0.38690
    MT_64 0.43439
    KISS 0.52137
    ISAAC 0.60310
    MT 0.61153
    WELL_1024_A 0.67584
    WELL_512_A 0.69410
    JDK 1.00000
    WELL_19937_A 1.11309
    WELL_19937_C 1.15391
    WELL_44497_A 1.17865
    WELL_44497_B 1.20130
  • Generating boolean values
    RNG identifier Score (normalized to the score of RandomSource.JDK)
    MT 0.93637
    MWC_256 0.95318
    WELL_19937_A 0.96010
    WELL_1024_A 0.96357
    WELL_44497_B 0.97277
    KISS 0.97344
    WELL_19937_C 0.99193
    JDK 1.00000
    ISAAC 1.00620
    WELL_44497_A 1.00850
    WELL_512_A 1.03589
    XOR_SHIFT_1024_S 1.10674
    SPLIT_MIX_64 1.12140
    MT_64 1.13390
    TWO_CMRES 1.13793
  • Sampling from a N(0,1) Gaussian distribution (MarsagliaNormalizedGaussianSampler implementation)
    RNG identifier Score (normalized to the score of RandomSource.JDK)
    SPLIT_MIX_64 0.41299
    XOR_SHIFT_1024_S 0.43226
    TWO_CMRES 0.50874
    MWC_256 0.51402
    MT_64 0.55053
    ISAAC 0.62246
    KISS 0.63574
    MT 0.65961
    WELL_512_A 0.76610
    WELL_1024_A 0.82318
    WELL_19937_A 0.93490
    WELL_44497_A 0.93664
    JDK 1.00000
    WELL_44497_B 1.01042
    WELL_19937_C 1.02012
  • Comparing BoxMullerNormalizedGaussianSampler, MarsagliaNormalizedGaussianSampler, ZigguratNormalizedGaussianSampler. Each score is normalized to the score of nextGaussian() method of java.util.Random.
    RNG identifier BoxMullerNormalizedGaussianSampler MarsagliaNormalizedGaussianSampler ZigguratNormalizedGaussianSampler
    ISAAC 0.98302 0.42238 0.25057
    JDK 1.06425 0.64978 0.34814
    KISS 0.95534 0.42419 0.22697
    MT 0.96351 0.44536 0.25375
    MT_64 0.88290 0.37917 0.22083
    MWC_256 0.92266 0.35825 0.19624
    SPLIT_MIX_64 0.83485 0.29606 0.17689
    TWO_CMRES 0.85873 0.35949 0.20117
    WELL_1024_A 1.02734 0.53311 0.27986
    WELL_19937_A 1.08683 0.63207 0.33016
    WELL_19937_C 1.09748 0.61706 0.35864
    WELL_44497_A 1.12428 0.61903 0.35108
    WELL_44497_B 1.12845 0.65736 0.37151
    WELL_512_A 1.01548 0.50523 0.27629
    XOR_SHIFT_1024_S 0.86013 0.30990 0.18612

5. Quality

This section reports results of performing "stress tests" that aim at detecting failures of an implementation to produce sequences of numbers that follow a uniform distribution.

Two different test suites were used:

The first column is the RNG identifier (see RandomSource). The second and third columns contain the number of tests which Dieharder and TestU01 respectively reported as below the accepted threshold for considering the sequence as uniformly random; hence, in this table, lower is better.

For each the two test suites, three runs were performed (using random seeds): Click on one of the numbers of the comma-separated list in order to see the text report of the corresponding run. Note: For Dieharder, a failure on the "Diehard Sums Test" can be ignored.

RNG identifier Dieharder TestU01 (BigCrush)
JDK 11, 12, 13 74, 72, 75
MT 0, 1, 0 3, 2, 2
WELL_512_A 0, 0, 0 7, 6, 6
WELL_1024_A 0, 0, 0 4, 4, 5
WELL_19937_A 0, 0, 0 3, 2, 3
WELL_19937_C 0, 1, 0 2, 2, 3
WELL_44497_A 0, 0, 0 2, 3, 3
WELL_44497_B 0, , 0 2, 2, 2
ISAAC 0, 0, 1 0, 1, 0
MT_64 0, 0, 1 3, 2, 3
SPLIT_MIX_64 0, 0, 0 2, 0, 0
XOR_SHIFT_1024_S 0, 0, 0 2, 0, 0
TWO_CMRES 1, 1, 1 0, 0, 1
MWC_256 0, 0, 0 0, 0, 0
KISS 0, 0, 0 1, 2, 0

6. Dependencies

Apache Commons RNG requires JDK 1.6+ and has no runtime dependencies.