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 Python code

Quickstart

Python package ojrandlib provides a generator object, or you can just call the non-object functions of the same name to get the library’s “default” generator. Here’s a simple example using the “Multiply with Carry” algorithm:

import ojrandlib as rl

g = rl.Generator("mwc8222")

print("  {:d}".format(g.rand(100)), " {:f}".format(g.next_double()))

Importing the module also loads the library, so both must be where Python can find them. In the example above we first create a new generator object. The generator is automatically seeded appropriately from whatever randomness is available from your operating system (we could have instead seeded it ourselves). Finally, the rand() and next_double() methods fetch a random integer and float, respectively.

Basic generator functions

Generator()

Creates a new generator using the algorithm specified by the single argument, either by name or number. With no argument, a reasonable default algorithm will be chosen. See the static methods below for how to get information on the available algorithms. The generator objects returned by this function 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).

seed()

With no argument, seeds the 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. You can also pass an integer value or a list of integers. If you need to save the value of a system-generated seed for reproduction later, you will have to instead call the function get_system_entropy() (see below) and seed with the result.

reseed()

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.

discard(count)

Advances the generator count 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 and seeded it, you can use it to produce random numbers in various ways. All of these functions can also be called statically to use the built-in “default” 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.

next16()

Produce a 16-bit random unsigned integer.

next64()

Produce a 64-bit random unsigned integer.

rand(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.

next_double()

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 in between with equal probability.

next_signed_double()

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.

next_exponential()

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

next_normal()

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

Non-generator functions

These static methods do not require a generator object because they provide information or services independent of any particular generator.

get_system_entropy(count)

Returns random (as a list of integers) from whatever source of randomness your OS provides. On Linux-like systems, these will be from /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. You should only need to use this function manually if you need both a good quality seed for a generator and need to save it for reproducibility later. Otherwise, simply using seed() on the generator is much simpler.

get_random_org(count)

Returns random bits (as a list of integers) 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).

algorithm_count()

Returns the number of algorithms available in the system.

algorithm_name(a)

Returns the name of the algorithm at the given index (beginning at 1). An argument of 0 returns the name of the “default” generator.