A pseudorandom number generator (PRNG) abstraction for C99.
librnd
requires that <stdlib.h>
defines the mrand48()
and jrand48()
functions. If arc4random()
and arc4random_uniform()
functions are
available, they are used in the default generator, otherwise mrand48()
is used.
librnd
generates pseudorandom 32 bit unsigned integers uniformly over a given
range. Here is the basic usage pattern:
#include "rnd.h"
// ...
struct rnd *rnd = rnd_alloc();
uint32_t number = rnd_next_uniform_value_in_range(rnd, 1, 100);
// number is in the interval [1, 100]
// ...
rnd_free(rnd);
The struct rnd
pointer holds information about the pseudorandom number
generator being used. The rnd_alloc()
function returns a struct rnd
that
uses arc4random()
if available, or mrand48()
otherwise.
The rnd_next_uniform_value_in_range()
function produces a pseudorandom number
uniformly from an inclusive lower bound to an inclusive upper bound.
Modulo bias
is accounted for.
The rnd_next_uniform_value()
function produces a number uniformly between
zero (inclusive) and a given exclusive upper bound:
uint32_t number = rnd_next_uniform_value(rnd, 100);
// number is in the interval [0, 99]
The rnd_next_value()
function produces a number between zero (inclusive) and
UINT32_MAX
(inclusive):
uint32_t number = rnd_next_value(rnd);
// number is in the interval [0, 4_294_967_295]
The global_rnd
variable points to a predefined instance of struct rnd
that
uses the default generator. global_rnd
doesn't need to be allocated or freed,
so it's useful as a step in refactoring code that uses a function like rand()
or arc4random()
to use librnd
.
uint32_t number = rnd_next_uniform_value(global_rnd, 100);
// number is in the interval [0, 99]
When testing or debugging, it can be useful to have control over the
pseudorandom numbers being generated. librnd
provides several alternate
generators.
The jrand48()
function generates a 32 bit pseudorandom integer using
generator state provided by the caller. The rnd_alloc_jrand48()
function
creates a struct rnd
pointer that uses jrand48()
and the provided initial
state. rnd_alloc_jrand48()
is great when you want a "normal" stream of
pseudorandom numbers, but you want the same stream every time.
struct rnd *rnd = rnd_alloc_jrand48((unsigned short[]){2, 3, 5});
// initial state is 2, 3, 5
uint32_t number1 = rnd_next_uniform_value(rnd, 100);
// number1 will always be 56
uint32_t number2 = rnd_next_uniform_value(rnd, 7);
// number2 will always be 1
// ...
rnd_free(rnd);
Similarly, mrand48()
uses the same generator as jrand48()
, but with a
shared internal buffer. Call the seed48()
function to initialize the
buffer before use.
The rnd_alloc_fake_X()
group of functions allocate different types of fake
pseudorandom number generators.
rnd_alloc_fake_ascending()
: the returned value increments for each call, from a given starting value; for bounded values, the returned value is modulo the range of possible valuesrnd_alloc_fake_fixed()
: always returns a fixed value, modulo the range of possible valuesrnd_alloc_fake_min()
: always returns the smallest value in the rangernd_alloc_fake_max()
: always returns the largest value in the rangernd_alloc_fake_median()
: always returns the median value of the range; for a range with an even number of possible values, returns the higher of the two middle values
Here is an example of rnd_alloc_fake_median()
:
struct rnd *rnd = rnd_alloc_fake_median();
uint32_t number1 = rnd_next_uniform_value(rnd, 100);
// number1 will always be 50
uint32_t number2 = rnd_next_uniform_value(rnd, 7);
// number2 will always be 3
// ...
rnd_free(rnd);
librnd
is written in C99 and should build on most modern POSIX compatible
operating systems with a recent GCC or LLVM compiler.
The source contains just two files: rnd.h
and rnd.c
.
The included build system produces a static library, librnd.a
.
You must have GNU Autoconf 2.69 or later and Automate 1.14 or later installed
$ autoreconf -i
$ mkdir tmp && cd tmp
$ ../configure
$ make
$ sudo make install
The rnd
distribution supports the standard GNU build steps.
$ mkdir tmp && cd tmp
$ ../configure
$ make
$ sudo make install
librnd
is made available under a BSD-style license; see the LICENSE file for
details.