Rill v0.13 Reference

Standard library · Randomness

random/rnd

Imported as import "random/rnd" as rnd, its names are then rnd.…. Every signature below is the one the checker infers.

Random numbers, from a generator that is a value.

PCG32 (O'Neill): a 64-bit state, a 32-bit output that passes the statistical tests, and one multiply and a few shifts a number. The generator is a Rng value — there is no hidden state — so a function that draws hands back the next generator with the number, and the same seed gives the same sequence on every run and every machine.

Not for secrets: a PCG stream can be predicted from its output. Keys and tokens come from random_i64(), which asks the operating system.

r = rnd.seed(42)
(n, r) = rnd.int_in(r, 1, 7)          # a die
n >= 1 && n <= 6                      # => true
(x, r) = rnd.float(r)
x >= 0.0 && x < 1.0                   # => true
(who, r) = rnd.pick(r, Cons("ada", Cons("bob", Nil)))
who != None                           # => true
deck = buf_int(3)
r = rnd.shuffle(r, deck)              # in place; the generator comes back

Types

Rng

  • Rng(state: Int, inc: Int)

Functions

fn seed(n: Int) -> Rng

A generator from a seed; two seeds, two streams.

(a, _) = rnd.next_int(rnd.seed(1))
(b, _) = rnd.next_int(rnd.seed(1))
a == b   # => true
(c, _) = rnd.next_int(rnd.seed(2))
a == c   # => false

fn seed2(n: Int, stream: Int) -> Rng

(a, _) = rnd.next_int(rnd.seed2(1, 1))
(b, _) = rnd.next_int(rnd.seed2(1, 2))
a == b   # => false

fn seed_from_os() -> Rng

A generator seeded by the operating system: different every run.

(a, _) = rnd.next_int(rnd.seed_from_os())
a >= 0   # => true

fn next_int(r: Rng) -> (Int, Rng)

The next 32-bit number, 0 .. 2^32 - 1, and the generator after it.

(n, r2) = rnd.next_int(rnd.seed(7))
n >= 0 && n < 4294967296   # => true

fn int_in(r: Rng, lo: Int, hi: Int) -> (Int, Rng)

A number in lo..hi, hi excluded, without the bias a % would have: a draw that lands in the ragged end of the range is taken again.

(n, _) = rnd.int_in(rnd.seed(7), 10, 20)
n >= 10 && n < 20   # => true

fn float(r: Rng) -> (Float, Rng)

A float in [0, 1), 53 random bits of it.

(x, _) = rnd.float(rnd.seed(7))
x >= 0.0 && x < 1.0   # => true

fn bool(r: Rng) -> (Bool, Rng)

(b, _) = rnd.bool(rnd.seed(7))
b == true || b == false   # => true

fn pick(r: Rng, xs: List('a)) -> (Option('a), Rng)

One of a list, or None of an empty one.

(x, _) = rnd.pick(rnd.seed(7), Cons("only", Nil))
x                                     # => Some(only)
(y, _) = rnd.pick(rnd.seed(7), Nil)
y == None                             # => true

fn shuffle(r: Rng, b: Buf(Int)) -> Rng

Fisher–Yates over a buffer, in place; the generator after it.

b = buf_int(4)
b[0] = 1
b[1] = 2
b[2] = 3
b[3] = 4
r = rnd.shuffle(rnd.seed(7), b)
b[0] + b[1] + b[2] + b[3]   # => 10

fn bytes(r: Rng, n: Int) -> (Str, Rng)

n random bytes, as a string of them.

(s, _) = rnd.bytes(rnd.seed(7), 16)
#s   # => 16

Tests

  • test_reference_stream
  • test_ranges
  • test_shuffle_keeps_everything