Modules

PCG

moduleSource
macOSLinuxWindowswasm

#import "PCG";

A small 32-bit-output permuted congruential generator (XSH-RR) over a 64-bit state.

Each procedure comes in two forms: one that takes the state as a *u64 you own, and one without a state that uses a single module-global u64. The global is shared by every thread and is not locked, so use your own state when more than one thread draws. The global starts at a fixed value, so an unseeded program sees the same numbers every run. The generator is not suitable for cryptography.

Procedures#

random_get2 overloads
(state: *u64) -> u32

The next 32 random bits, advancing the state. Any u64 is a valid state, including 0.

state: u64;
random_seed(*state, 42);
assert(state == 0x91778aed87ee5eb1); // seeding sets the state from the seed
assert(random_get(*state) == 0x75830bbd);
assert(random_get(*state) == 0x0e6dfdb2);
↗
(state: *u64, range: u32) -> u32

A value in [0, bound) without modulo bias, drawn by rejecting the few low outputs that would make some results likelier. bound must not be 0 (an assert fails); with bound 1 the result is always 0.

state: u64;
random_seed(*state, 9);
counts: [6] int;
for 1..6000 counts[random_get_within_bound(*state, 6)] += 1;
for counts assert(it > 800 && it < 1200);
↗
(state: *u64, range: u32) -> u32

The same as random_get_within_bound, kept as a second name for programs that call it.

random_seed2 overloads
(state: *u64, new_seed: u32)

Starts the generator from new_seed: the state becomes seed * 6364136223846793005 + 1442695040888963407 (wrapping), so the first draw comes from that value. Equal seeds give equal sequences.

a, b: u64;
random_seed(*a, 1234);
random_seed(*b, 1234);
for 1..10 assert(random_get(*a) == random_get(*b));
↗
(state: *u64, min: float, max: float) -> float

A float between min and max, interpolated from random_get_zero_to_one. The result is clamped into the range (so max itself can occur); equal bounds give that value.

state: u64;
random_seed(*state, 7);
for 1..1000 {
    v := random_get_within_range(*state, -1.0, 2.0);
    assert(v >= -1 && v <= 2);
    w := random_get_within_range(*state, 2.0, -1.0);
    assert(w >= -1 && w <= 2);
}
assert(random_get_within_range(*state, 5.0, 5.0) == 5);
↗