module rand

module lib/rand.mu

import "rand"

rand provides a small pseudo-random number generator.

This is a Lehmer generator over the Mersenne prime 2^61-1: deterministic, reproducible from a given seed, and adequate for shuffling a deck or picking a colour. It is NOT suitable for anything where predicting the next value matters -- keys, tokens, nonces -- because the whole sequence follows from any one value.

The seed is taken from the clock on first use. Call seed() to make a run reproducible.

Imports

Functions

below#

fn below(bound)

below returns a pseudo-random integer in [0, bound).

Source lib/rand.mu:65
fn below(bound) {
    if !typing.is_int(bound) {
        return error("rand.below expects integer bound, got " + type(bound))
    }
    if bound <= 0 {
        return error("rand.below expects a positive bound, got " + str(bound))
    }
    return int() % bound
}

between#

fn between(low, high)

between returns a pseudo-random integer in [low, high], both inclusive.

Source lib/rand.mu:76
fn between(low, high) {
    if !typing.is_int(low) {
        return error("rand.between expects integer low, got " + type(low))
    }
    if !typing.is_int(high) {
        return error("rand.between expects integer high, got " + type(high))
    }
    if low > high {
        return error("rand.between expects low <= high, got " + str(low) + " > " + str(high))
    }
    return low + below(high - low + 1)
}

choice#

fn choice(items)

choice returns a pseudo-random element of a non-empty list.

Source lib/rand.mu:90
fn choice(items) {
    if !typing.is_list(items) {
        return error("rand.choice expects list items, got " + type(items))
    }
    if len(items) == 0 {
        return error("rand.choice expects a non-empty list")
    }
    return items[below(len(items))]
}

int#

fn int()

int returns the next pseudo-random non-negative integer.

Source lib/rand.mu:55
fn int() {
    _ensure_seeded()
    _state = (_state * _MULTIPLIER) % _MODULUS
    if _state < 0 {
        _state = -_state
    }
    return _state
}

seed#

fn seed(value)

seed fixes the generator's starting point, making a run reproducible. Any integer will do; 0 is replaced with 1, since 0 is this generator's one fixed point and would make every subsequent value 1.

Source lib/rand.mu:23
fn seed(value) {
    if !typing.is_int(value) {
        return error("rand.seed expects integer value, got " + type(value))
    }
    _state = value % _MODULUS
    if _state < 0 {
        _state = -_state
    }
    if _state == 0 {
        _state = 1
    }
    return nil
}

shuffle#

fn shuffle(items)

shuffle returns a new list holding the same elements in pseudo-random order, leaving the input untouched. Fisher-Yates, so every ordering is equally likely as far as the generator is.

Source lib/rand.mu:103
fn shuffle(items) {
    if !typing.is_list(items) {
        return error("rand.shuffle expects list items, got " + type(items))
    }
    out := []
    i := 0
    while i < len(items) {
        out = append(out, items[i])
        i = i + 1
    }
    i = len(out) - 1
    while i > 0 {
        j := below(i + 1)
        swap := out[i]
        out[i] = out[j]
        out[j] = swap
        i = i - 1
    }
    return out
}

Internal helpers

Underscore-prefixed names are implementation detail. They are listed so the module's source reads without surprises, not as API — they may change at any time.

_MODULUS
_MULTIPLIER
_ensure_seeded()_ensure_seeded seeds from the clock the first time a value is asked for.
_state