Pseudo-random number generation library and tools. Part of the OneJoker project.

Project maintained by Lee Daniel Crocker
Lee's blog is etceterology.

onejoker
CC-0: To the extent possible under law, I, Lee Daniel Crocker waive all copyright and related or neighboring rights to all creative works original to me.

Using the library in your C++ code

Quickstart

The C++ functions are in the namespace oj. There are two objects: Seed is just a vector of unsigned ints, and Generator which encapsulates the actual PRNG algorithms. As with the C API, there is also a built-in “default” generator that can be accessed by functions without the need to create a generator object. Here’s a short example of using the library to print 10 random numbers in the range 0 to 99, using the Mersenne Twister algorithm.

#include <iostream>
using namespace std;

#include "ojrandlib.h"
using namespace oj;

int main(int argc, char *argv[]) {
    Generator g("mt19937");

    for (int i = 0; i < 10; ++i) {
        cout << g.rand(100) << " ";
    }
}

The single header file ojrandlib.h has all the needed declarations and definitions for the library. You will also have to link your code to the library (with gcc, for example, add -lojrand to the link command). We first create a new generator object with the algorithm we want. The generator is automatically seeded appropriately from whatever randomness is available from your operating system (you could seed it yourself if you wanted a reproducible sequence). Finally, g.rand(100) fetches a random integer in the range 0 to 99. If we just want to use the built-in default generator, you can skip creating the generator object and just call the function rand().

Basic generator functions

oj::Generator(), Generator(const char *name), Generator(int alg)

Called without arguments, it will create a generator object with an appropriate default algorithm, and seed it from system randomness. You can also pass an argument which is the name of an available algorithm, or a number from 1 to the number of algorithms available. See the non-object functions below for how to get information on the available algorithms. The generator objects returned are totally independent of each other, regardless of algorithm. In particular, if you create two generators with the same algorithm and same seed, they will independently produce the same stream of random numbers (this can be handy for writing test programs, for example).

oj::Generator::seed(), seed(int s), seed(Seed sv)

With no argument, seeds the given generator with random values derived from whatever entropy is available from your operating system. The size of the seed will be chosen to suit the algorithm. A single argument can either be an integer seed, or a Seed object (which is a vector of unsigned ints). If you need to save the value of a system-generated seed for reproduction later, you can instead call oj::getSystemEntropy() (see below) to get a seed, and pass that value to the function.

oj::Generator::reseed(Seed sv)

Applies a new seed to an existing generator to change its state “on the fly” without re-initializing. This function should not be needed by most applications. It could be used, for example, to occasionally add extra system entropy to a generator to make it more cryptographically secure. This eliminates reproducibility.

oj::Generator::discard(int count)

Advances the generator the given number of steps wihout producing actual output. This is roughly equivalent to calling next32() (see below) count times, though it is faster due to reduced function call overhead. Some generator algorithms benefit from discarding some number of values after initialization before using their output.

Producing output

Now that you’ve created and generator, you can use it to produce random numbers in various ways. All of these functions also exist as non-object functions in the oj namespace to use the default generator.

uint32_t oj::Generator::next32()

Produces a random 32-bit unsigned integer. All of the algorithms included in ojrandlib are natively 32-bit generators, so the most basic way to get random values is to get them as 32-bit unsigned integers. All of the other producer functions are based on this one.

uint16_t oj::Generator::next16()

Produce a 16-bit random unsigned integer.

uint64_t oj::Generator::next64()

Produce a 64-bit random unsigned integer.

int oj::Generator::rand(int limit)

Produces a random integer in the range 0 to (limit-1). This is the most useful function for randomly choosing from among a small set of alternatives, for example, selecting a random card from a deck of cards. The numbers are guaranteed to be balanced. That is, if called with a limit of 3, you will get the values 0, 1, and 2 with exactly equal probability. The maximum limit for this function is 32768.

double oj::Generator:nextDouble()

Produces a random double value uniformly distributed in the half-open interval [0.0, 1.0). That is, it may produce the value 0.0, but will never produce 1.0, and will produce every representable value (with a 53-bit mantissa) in between with equal probability.

double oj::Generator::nextSignedDouble()

Produces a random double value uniformly distributed in the open interval (-1.0, 1.0). That is, it will never produce the values -1.0 or 1.0, and will produce every representable value in between with equal probability.

double oj::Generator::nextExponential()

Produces a random double value with a probability density of e-x.

double oj::Generator::nextNormal()

Produces a random double value normally distributed about a mean of 0.0 with a standard deviation of 1.0.

Non-generator functions

These functions do not take a generator object because they provide information or services independent of any particular generator.

oj::getSystemEntropy(Seed &sv, int count)

Fills the given Seed vector with random bits from whatever source of randomness your OS provides. On Linux-like systems, this will be /dev/urandom. On Windows, CryptGenRandom() from the cryptography library will be used. If neither of these is available, the system time and process ID will be used.

oj::getRandomOrg(Seed &sv, int count)

Fills the given seed vector with bits from the website random.org, which provides random numbers based on atmospheric noise. It is recommended that this be used for seeding PRNGs or other applications that don’t need large quantities of random numbers. The service is limited in speed by your Internet connection and limited in quantity to a daily quota, because it is a free service (although you can pay them for a larger quota).

int oj::algorithmCount()

Returns the number of algorithms available in the system.

char *oj::algorithmName(int a)

Returns the name of the algorithm at the given index. Algorithms are identified by an integer from 1 to the number available. So, to list all the available algorithms by name, one could use code like the following:

int n = oj::algorithmCount();

for (int i = 1; i <= n; ++i) {
    printf("%s\n", oj::algorithmName(i));
}

Passing a value of 0 will return the name of the “default” algorithm.