Files
skills/docs/foundation/random/pseudo-random/src/algorithms/mulberry32.md
2026-05-29 08:20:56 +01:00

2.3 KiB

algorithms/mulberry32

Purpose

Mulberry32Rng implements the Mulberry32 PRNG — a compact 32-bit linear-congruential-plus-mix generator with a period of roughly 2^32. It is the smallest SeededRng in the package (one 32-bit word of state) and is ideal for UI seedings, per-card shuffles, procedural decorations and any workload where replayability matters but cryptographic strength does not.

The implementation is byte-identical to the inline generator shipped inside @suaveplan/testing's seededRng, so code migrated between the two produces the same draws.

Features

  • Single uint32 of state; ~1-cycle nextUint32 cost
  • Implements the full SeededRng contract (skip, at, fork, checkpoint, restore)
  • Algorithm-tagged checkpoint prevents cross-algorithm restore bugs
  • Typed errors on malformed state or invalid arguments

Usage: Basic Example

import { Mulberry32Rng } from "@suaveplan/pseudo-random";

const rng = new Mulberry32Rng("level-1");
console.log(rng.nextFloat());
console.log(rng.nextUint32());

Usage: Advanced Example

import { Mulberry32Rng } from "@suaveplan/pseudo-random";

const parent = new Mulberry32Rng("game-42");
const encounterRng = parent.fork("encounter");
const lootRng = parent.fork("loot");

const save = parent.checkpoint();
// ... simulate many turns ...
parent.restore(save); // back to the turn-0 state

API Reference

  • new Mulberry32Rng(seed: string | number) — normalises the seed through normalizeSeed.
  • nextUint32() / nextFloat() — uniform draws.
  • skip(n) — advance the stream by n uint32 draws; n must be a non-negative integer.
  • at(offset) — clone the generator and skip offset draws on the clone. Does not mutate this.
  • fork(id) — derive a child generator keyed on (state, position, id).
  • checkpoint() / restore(cp) — snapshot and reinstate state; restore validates the algorithm tag.

Implementation Notes

The generator advances by state = (state + 0x6d2b79f5) | 0, then runs two Math.imul mixing rounds before returning the high-entropy output. at(offset) is O(offset) because Mulberry32 has no closed-form jump; if you need O(1) seek use CounterRng instead. Fork keys include the parent's current position so repeated forks at different moments yield independent streams.