Mojo Random Numbers
Random numbers power simulations, games, cryptography, statistical sampling, machine learning data augmentation, and testing. Mojo provides a native random module for fast random number generation, and Python's random and numpy.random are also available through the interop layer for richer distributions.
What "Random" Means in Computing
True random: based on physical unpredictability (radioactive decay,
atmospheric noise) — used in cryptography.
Pseudo-random: deterministic sequence that looks random, produced
by a mathematical formula starting from a seed value.
Same seed → same sequence (every time, on every machine).
Different seed → different sequence.
Seed 42: [0.37, 0.95, 0.73, 0.15, 0.60, ...]
Seed 7: [0.07, 0.43, 0.86, 0.54, 0.20, ...]
Reproducibility is a feature — fix the seed in tests and experiments
so results are the same every run.
Mojo's random Module
from random import random_float64, random_si64, random_ui64, seed
fn main():
seed(42) # fix the seed for reproducibility
# Float in [0.0, 1.0)
var f = random_float64()
print(f) # 0.37454... (deterministic with seed 42)
# Signed integer in the full Int64 range
var si = random_si64(0, 100) # in [0, 100)
print(si)
# Unsigned integer
var ui = random_ui64(1, 7) # simulates a die roll [1, 7)
print(ui)
Generating a Range of Random Values
from random import random_float64, seed
fn main():
seed(0)
var samples = List[Float64]()
for _ in range(10):
samples.append(random_float64())
for i in range(len(samples)):
print(samples[i], end=" ")
print("")
Distribution of random_float64(): 0.0 ──────────────────────────── 1.0 Every point equally likely (uniform distribution) ||||||||||||||||||||||||||||||||||| Each call returns one point in this range.
Scaling to a Custom Range
Scale a [0, 1) float to any [low, high) range with a simple formula.
from random import random_float64, seed
fn random_in_range(low: Float64, high: Float64) -> Float64:
return low + random_float64() * (high - low)
fn main():
seed(1)
for _ in range(5):
var temp = random_in_range(20.0, 40.0) # random temperature
print(temp)
Scaling formula: raw ∈ [0.0, 1.0) scaled = low + raw × (high - low) Example: low=20, high=40, raw=0.37 scaled = 20 + 0.37 × 20 = 20 + 7.4 = 27.4
Simulating a Coin Flip
from random import random_float64, seed
fn coin_flip() -> String:
return "Heads" if random_float64() < 0.5 else "Tails"
fn main():
seed(99)
var heads = 0
var tails = 0
let trials = 1000
for _ in range(trials):
if coin_flip() == "Heads":
heads += 1
else:
tails += 1
print("Heads:", heads, "| Tails:", tails)
# Approximately 500/500 with any large trial count
Probability diagram:
[0.0 ────────── 0.5 ────────── 1.0)
Tails │ Heads
0.5 (threshold)
Shuffling a List
from random import random_ui64, seed
fn shuffle(inout data: List[Int]):
var n = len(data)
for i in range(n - 1, 0, -1):
var j = Int(random_ui64(0, UInt64(i + 1)))
var temp = data[i]
data[i] = data[j]
data[j] = temp
fn main():
seed(5)
var deck = List[Int]()
for i in range(1, 14): # cards 1–13
deck.append(i)
print("Before:", end=" ")
for i in range(len(deck)):
print(deck[i], end=" ")
print("")
shuffle(deck)
print("After: ", end=" ")
for i in range(len(deck)):
print(deck[i], end=" ")
print("")
Fisher-Yates shuffle (how shuffle() works): Start from the last element and work backward. At each position i, pick a random index j in [0, i]. Swap element i with element j. This gives every permutation exactly equal probability.
Sampling Without Replacement
from random import random_ui64, seed
fn sample(data: List[Int], k: Int) -> List[Int]:
# Copy data into a working list
var pool = List[Int]()
for i in range(len(data)):
pool.append(data[i])
var result = List[Int]()
for _ in range(k):
var idx = Int(random_ui64(0, UInt64(len(pool))))
result.append(pool[idx])
# Remove chosen element to avoid re-picking
pool[idx] = pool[len(pool) - 1]
_ = pool.pop()
return result
fn main():
seed(7)
var numbers = List[Int](1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
var chosen = sample(numbers, 3)
for i in range(len(chosen)):
print(chosen[i], end=" ") # 3 unique random picks
print("")
Richer Distributions via NumPy
from python import Python
fn main() raises:
var np = Python.import_module("numpy")
var rng = np.random.default_rng(seed=42)
# Normal / Gaussian distribution
var normal = rng.standard_normal(size=5)
print("Normal:", normal)
# Exponential distribution (e.g., wait times)
var exp_vals = rng.exponential(scale=2.0, size=5)
print("Exponential:", exp_vals)
# Binomial (e.g., number of heads in 10 coin flips, repeated 5 times)
var binom = rng.binomial(n=10, p=0.5, size=5)
print("Binomial:", binom)
# Poisson (e.g., events per time period)
var pois = rng.poisson(lam=3.0, size=5)
print("Poisson:", pois)
Distribution shapes: Uniform: ████████████████ (flat — all values equally likely) Normal: ▄▄████▄▄ (bell curve — mean is most common) Exponential: █▄▄░░░░░░░░░░░ (many small, few large values) Poisson: ▄▄███▄░░ (count of events in fixed time)
Practical Example: Monte Carlo π Estimation
from random import random_float64, seed
fn estimate_pi(trials: Int) -> Float64:
seed(0)
var inside = 0
for _ in range(trials):
var x = random_float64()
var y = random_float64()
if x*x + y*y <= 1.0: # point inside unit circle?
inside += 1
return 4.0 * Float64(inside) / Float64(trials)
fn main():
print(estimate_pi(10_000)) # ≈ 3.14
print(estimate_pi(1_000_000)) # ≈ 3.1416
Monte Carlo π idea: ┌──────────────┐ │ ╭────────╮ │ ← unit square [0,1]×[0,1] │ ╱ ╲ │ ││ (quarter) ││ ← quarter circle, radius 1 │ ╲ ╱ │ │ ╰────────╯ │ └──────────────┘ Area of quarter circle = π/4 Ratio of hits inside circle to total points ≈ π/4 So π ≈ 4 × (hits / total)
Key Takeaways
Call seed(n) before generating numbers to make results reproducible — essential in testing and scientific experiments. random_float64() returns a float in [0.0, 1.0). Scale it to any range with low + raw * (high - low). Use random_si64(lo, hi) and random_ui64(lo, hi) for integer ranges. Implement the Fisher-Yates algorithm for unbiased list shuffling. Use NumPy's rng for non-uniform distributions (normal, exponential, Poisson). Monte Carlo methods use large numbers of random samples to approximate mathematical constants and integrals.
