Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@

TARGETS = pcg32-global-demo pcg32-demo pcg32x2-demo

CFLAGS += -O3
CFLAGS += -Wall -Wextra -Waggregate-return -Wcast-align -Wcast-qual \
-Wdisabled-optimization -Wdiv-by-zero -Wendif-labels \
-Wformat-extra-args -Wformat-nonliteral -Wformat-security \
-Wformat-y2k -Wimplicit -Wimport -Winit-self -Winline -Winvalid-pch \
-Wmissing-declarations -Wno-missing-format-attribute \
-Wmissing-include-dirs -Wmultichar -Wpacked -Wpointer-arith \
-Wreturn-type -Wsequence-point -Wsign-compare -Wstrict-aliasing \
-Wstrict-aliasing=2 -Wswitch -Wswitch-default \
-Wno-unused -Wvariadic-macros -Wwrite-strings -Wc++-compat \
-Werror=declaration-after-statement \
-Werror=implicit-function-declaration -Wmissing-prototypes \
-Werror=nested-externs -Werror=old-style-definition \
-Werror=strict-prototypes -Werror=missing-braces

all: $(TARGETS)

clean:
Expand Down
32 changes: 16 additions & 16 deletions pcg32-demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

int main(int argc, char** argv)
{
// Read command-line options
/* Read command-line options */

int rounds = 5;
bool nondeterministic_seed = false;
Expand All @@ -54,30 +54,30 @@ int main(int argc, char** argv)
rounds = atoi(argv[0]);
}

// In this version of the code, we'll use a local rng, rather than the
// global one.
/* In this version of the code, we'll use a local rng, rather than the
global one. */

pcg32_random_t rng;

// You should *always* seed the RNG. The usual time to do it is the
// point in time when you create RNG (typically at the beginning of the
// program).
//
// pcg32_srandom_r takes two 64-bit constants (the initial state, and the
// rng sequence selector; rngs with different sequence selectors will
// *never* have random sequences that coincide, at all) - the code below
// shows three possible ways to do so.
/* You should *always* seed the RNG. The usual time to do it is the
point in time when you create RNG (typically at the beginning of the
program). */

/* pcg32_srandom_r takes two 64-bit constants (the initial state, and the
rng sequence selector; rngs with different sequence selectors will
*never* have random sequences that coincide, at all) - the code below
shows three possible ways to do so. */

if (nondeterministic_seed) {
// Seed with external entropy -- the time and some program addresses
// (which will actually be somewhat random on most modern systems).
// A better solution, entropy_getbytes, using /dev/random, is provided
// in the full library.
/* Seed with external entropy -- the time and some program addresses
(which will actually be somewhat random on most modern systems)
A better solution, entropy_getbytes, using /dev/random, is provided
in the full library. */

pcg32_srandom_r(&rng, time(NULL) ^ (intptr_t)&printf,
(intptr_t)&rounds);
} else {
// Seed with a fixed constant
/* Seed with a fixed constant */

pcg32_srandom_r(&rng, 42u, 54u);
}
Expand Down
24 changes: 12 additions & 12 deletions pcg32-global-demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

int main(int argc, char** argv)
{
// Read command-line options
/* Read command-line options */

int rounds = 5;
bool nondeterministic_seed = false;
Expand All @@ -54,17 +54,17 @@ int main(int argc, char** argv)
rounds = atoi(argv[0]);
}

// In this version of the code, we'll use the global rng, rather than a
// local one.
/* In this version of the code, we'll use the global rng, rather than a
local one. */

// You should *always* seed the RNG. The usual time to do it is the
// point in time when you create RNG (typically at the beginning of the
// program).
//
// pcg32_srandom_r takes two 64-bit constants (the initial state, and the
// rng sequence selector; rngs with different sequence selectors will
// *never* have random sequences that coincide, at all) - the code below
// shows three possible ways to do so.
/* You should *always* seed the RNG. The usual time to do it is the
point in time when you create RNG (typically at the beginning of the
program). */

/* pcg32_srandom_r takes two 64-bit constants (the initial state, and the
rng sequence selector; rngs with different sequence selectors will
*never* have random sequences that coincide, at all) - the code below
shows three possible ways to do so. */

if (nondeterministic_seed) {
// Seed with external entropy -- the time and some program addresses
Expand All @@ -74,7 +74,7 @@ int main(int argc, char** argv)

pcg32_srandom(time(NULL) ^ (intptr_t)&printf, (intptr_t)&rounds);
} else {
// Seed with a fixed constant
/* Seed with a fixed constant */

pcg32_srandom(42u, 54u);
}
Expand Down
30 changes: 15 additions & 15 deletions pcg32x2-demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void pcg32x2_srandom_r(pcg32x2_random_t* rng, uint64_t seed1, uint64_t seed2,
uint64_t seq1, uint64_t seq2)
{
uint64_t mask = ~0ull >> 1;
// The stream for each of the two generators *must* be distinct
/* The stream for each of the two generators *must* be distinct */
if ((seq1 & mask) == (seq2 & mask))
seq2 = ~seq2;
pcg32_srandom_r(rng->gen, seed1, seq1);
Expand Down Expand Up @@ -89,7 +89,7 @@ int dummy_global;

int main(int argc, char** argv)
{
// Read command-line options
/* Read command-line options */

int rounds = 5;
bool nondeterministic_seed = false;
Expand All @@ -111,27 +111,27 @@ int main(int argc, char** argv)

pcg32x2_random_t rng;

// You should *always* seed the RNG. The usual time to do it is the
// point in time when you create RNG (typically at the beginning of the
// program).
//
// pcg32x2_srandom_r takes four 64-bit constants (the initial state, and
// the rng sequence selector; rngs with different sequence selectors will
// *never* have random sequences that coincide, at all) - the code below
// shows three possible ways to do so.
/* You should *always* seed the RNG. The usual time to do it is the
point in time when you create RNG (typically at the beginning of the
program). */

/* pcg32x2_srandom_r takes four 64-bit constants (the initial state, and
the rng sequence selector; rngs with different sequence selectors will
*never* have random sequences that coincide, at all) - the code below
shows three possible ways to do so. */

if (nondeterministic_seed) {
// Seed with external entropy -- the time and some program addresses
// (which will actually be somewhat random on most modern systems).
// A better solution, entropy_getbytes, using /dev/random, is provided
// in the full library.
/* Seed with external entropy -- the time and some program addresses
(which will actually be somewhat random on most modern systems).
A better solution, entropy_getbytes, using /dev/random, is provided
in the full library. */

pcg32x2_srandom_r(&rng, time(NULL) ^ (intptr_t)&printf,
~time(NULL) ^ (intptr_t)&pcg32_random_r,
(intptr_t)&rounds,
(intptr_t)&dummy_global);
} else {
// Seed with a fixed constant
/* Seed with a fixed constant */

pcg32x2_srandom_r(&rng, 42u, 42u, 54u, 54u);
}
Expand Down
64 changes: 32 additions & 32 deletions pcg_basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@

#include "pcg_basic.h"

// state for global RNGs
/* state for global RNGs */

static pcg32_random_t pcg32_global = PCG32_INITIALIZER;

// pcg32_srandom(initstate, initseq)
// pcg32_srandom_r(rng, initstate, initseq):
// Seed the rng. Specified in two parts, state initializer and a
// sequence selection constant (a.k.a. stream id)
/* pcg32_srandom(initstate, initseq)
* pcg32_srandom_r(rng, initstate, initseq):
* Seed the rng. Specified in two parts, state initializer and a
* sequence selection constant (a.k.a. stream id) */

void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
Expand All @@ -53,9 +53,9 @@ void pcg32_srandom(uint64_t seed, uint64_t seq)
pcg32_srandom_r(&pcg32_global, seed, seq);
}

// pcg32_random()
// pcg32_random_r(rng)
// Generate a uniformly distributed 32-bit random number
/* pcg32_random()
* pcg32_random_r(rng)
* Generate a uniformly distributed 32-bit random number */

uint32_t pcg32_random_r(pcg32_random_t* rng)
{
Expand All @@ -66,41 +66,41 @@ uint32_t pcg32_random_r(pcg32_random_t* rng)
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

uint32_t pcg32_random()
uint32_t pcg32_random(void)
{
return pcg32_random_r(&pcg32_global);
}


// pcg32_boundedrand(bound):
// pcg32_boundedrand_r(rng, bound):
// Generate a uniformly distributed number, r, where 0 <= r < bound
/* pcg32_boundedrand(bound):
* pcg32_boundedrand_r(rng, bound):
* Generate a uniformly distributed number, r, where 0 <= r < bound */

uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound)
{
// To avoid bias, we need to make the range of the RNG a multiple of
// bound, which we do by dropping output less than a threshold.
// A naive scheme to calculate the threshold would be to do
//
// uint32_t threshold = 0x100000000ull % bound;
//
// but 64-bit div/mod is slower than 32-bit div/mod (especially on
// 32-bit platforms). In essence, we do
//
// uint32_t threshold = (0x100000000ull-bound) % bound;
//
// because this version will calculate the same modulus, but the LHS
// value is less than 2^32.
/* To avoid bias, we need to make the range of the RNG a multiple of
* bound, which we do by dropping output less than a threshold.
* A naive scheme to calculate the threshold would be to do
*
* uint32_t threshold = 0x100000000ull % bound;
*
* but 64-bit div/mod is slower than 32-bit div/mod (especially on
* 32-bit platforms). In essence, we do
*
* uint32_t threshold = (0x100000000ull-bound) % bound;
*
* because this version will calculate the same modulus, but the LHS
* value is less than 2^32. */

uint32_t threshold = -bound % bound;

// Uniformity guarantees that this loop will terminate. In practice, it
// should usually terminate quickly; on average (assuming all bounds are
// equally likely), 82.25% of the time, we can expect it to require just
// one iteration. In the worst case, someone passes a bound of 2^31 + 1
// (i.e., 2147483649), which invalidates almost 50% of the range. In
// practice, bounds are typically small and only a tiny amount of the range
// is eliminated.
/* Uniformity guarantees that this loop will terminate. In practice, it
* should usually terminate quickly; on average (assuming all bounds are
* equally likely), 82.25% of the time, we can expect it to require just
* one iteration. In the worst case, someone passes a bound of 2^31 + 1
* (i.e., 2147483649), which invalidates almost 50% of the range. In
* practice, bounds are typically small and only a tiny amount of the range
* is eliminated. */
for (;;) {
uint32_t r = pcg32_random_r(rng);
if (r >= threshold)
Expand Down
32 changes: 16 additions & 16 deletions pcg_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,36 +37,36 @@
extern "C" {
#endif

struct pcg_state_setseq_64 { // Internals are *Private*.
uint64_t state; // RNG state. All values are possible.
uint64_t inc; // Controls which RNG sequence (stream) is
// selected. Must *always* be odd.
struct pcg_state_setseq_64 { /* Internals are *Private*. */
uint64_t state; /* RNG state. All values are possible. */
uint64_t inc; /* Controls which RNG sequence (stream) is */
/* selected. Must *always* be odd. */
};
typedef struct pcg_state_setseq_64 pcg32_random_t;

// If you *must* statically initialize it, here's one.
/* If you *must* statically initialize it, here's one. */

#define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }

// pcg32_srandom(initstate, initseq)
// pcg32_srandom_r(rng, initstate, initseq):
// Seed the rng. Specified in two parts, state initializer and a
// sequence selection constant (a.k.a. stream id)
/* pcg32_srandom(initstate, initseq)
* pcg32_srandom_r(rng, initstate, initseq):
* Seed the rng. Specified in two parts, state initializer and a
* sequence selection constant (a.k.a. stream id) */

void pcg32_srandom(uint64_t initstate, uint64_t initseq);
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate,
uint64_t initseq);

// pcg32_random()
// pcg32_random_r(rng)
// Generate a uniformly distributed 32-bit random number
/* pcg32_random()
* pcg32_random_r(rng):
* Generate a uniformly distributed 32-bit random number */

uint32_t pcg32_random(void);
uint32_t pcg32_random_r(pcg32_random_t* rng);

// pcg32_boundedrand(bound):
// pcg32_boundedrand_r(rng, bound):
// Generate a uniformly distributed number, r, where 0 <= r < bound
/* pcg32_boundedrand(bound)
* pcg32_boundedrand_r(rng, bound):
* Generate a uniformly distributed number, r, where 0 <= r < bound */

uint32_t pcg32_boundedrand(uint32_t bound);
uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound);
Expand All @@ -75,4 +75,4 @@ uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound);
}
#endif

#endif // PCG_BASIC_H_INCLUDED
#endif /* PCG_BASIC_H_INCLUDED */