Skip to main content
The random module provides a comprehensive collection of pseudorandom number generator (PRNG) algorithms, from historical curiosities to modern high-quality generators. Each algorithm is self-contained, educational, and operates on caller-supplied state with no hidden globals.
Security notice: None of these PRNGs are cryptographically secure. For security-sensitive applications, read from /dev/urandom directly.

Seeding functions

Generate initial seeds from system entropy.
Generate a 32-bit seed from /dev/urandom.Returns: Unsigned 32-bit integer seed
seed=$(random::seed32)
echo "Seed: $seed"
Implementation:
od -An -N4 -tu4 /dev/urandom 2>/dev/null | tr -d ' \n' || echo "$RANDOM"
Generate a 64-bit seed from /dev/urandom.Returns: 64-bit integer seed (may be negative in bash)
seed=$(random::seed64)
Note: Falls back to $RANDOM if /dev/urandom is unavailable.

Native bash PRNG

Bash’s built-in $RANDOM variable (15-bit LCG). Quality: Poor | Period: 2^15 | Use: Quick throwaway needs only
Return bash’s built-in random number.Returns: Integer in range [0, 32767]
value=$(random::native)
echo "Random: $value"
Implementation:
echo "$RANDOM"
Generate random integer in specified range (inclusive).Parameters:
  • min - Minimum value
  • max - Maximum value
Returns: Random integer in [min, max]
dice=$(random::native::range 1 6)
echo "Rolled: $dice"

Middle square method

John von Neumann, 1946 - The original PRNG algorithm. Quality: Very poor | Period: Variable, often very short | Use: Historical demonstration
Degenerates to zero for many seeds. Short cycles are common. Use only for educational purposes.
Generate next value using middle square method.Parameters:
  • seed - Current state (4-digit number recommended)
Returns: Next value (4-digit middle square extract)
state=1234
state=$(random::middle_square $state)
echo "Next: $state"
Algorithm:
  1. Square the seed
  2. Extract middle 4 digits
  3. Return as next value
Example sequence from seed 1234:
1234 → 5227 → 3215 → 3362 → ...

Linear congruential generator (LCG)

Classic algorithm used in early C stdlib rand() implementations. Quality: Poor to moderate | Period: 2^32 | Use: Simple simulations, not security
LCG with Numerical Recipes parameters (Press et al.).Parameters:
  • state - Current state
Returns: Next state (also the output value)
state=$(random::seed32)
state=$(random::lcg $state)
echo "Random: $state"
Formula: state = (state × 1664525 + 1013904223) mod 2^32
LCG with glibc rand() parameters.Parameters:
  • state - Current state
Returns: Next state
state=$(random::lcg::glibc $state)
Formula: state = (state × 1103515245 + 12345) mod 2^32

Xorshift family

George Marsaglia, 2003 - Simple bitwise operations only. Quality: Moderate to good | Use: Fast non-secure generation
32-bit xorshift PRNG.Quality: Moderate | Period: 2^32 - 1Parameters:
  • state - Current state (must not be 0)
Returns: Next state (also the output value)
state=$(random::seed32)
state=$(random::xorshift32 $state)
echo "Value: $state"
Implementation:
x=$(( x ^ (x << 13) ))
x=$(( x ^ (x >> 17) ))
x=$(( x ^ (x << 5) ))
64-bit xorshift PRNG.Quality: Moderate | Period: 2^64 - 1Parameters:
  • state - Current state (must not be 0)
Returns: Next state
state=$(random::seed64)
state=$(random::xorshift64 $state)

Xorshift128+ (scrambled linear)

Sebastiano Vigna, 2014 - Used in V8, SpiderMonkey, and WebKit Math.random(). Quality: Good (passes most BigCrush tests) | Period: 2^128 - 1 | Use: General purpose
Generate next value from xorshift128+ algorithm.Parameters:
  • s0 - State component 0 (64-bit)
  • s1 - State component 1 (64-bit)
Returns: “result s0_new s1_new” (space-separated)
s0=$(random::seed64)
s1=$(random::seed64)

read -r val s0 s1 <<< "$(random::xorshiftr128plus $s0 $s1)"
echo "Random value: $val"

# Generate more values
read -r val s0 s1 <<< "$(random::xorshiftr128plus $s0 $s1)"
Note: Caller must unpack and pass updated state on next call.

Xoshiro256 family

Blackman & Vigna, 2018 - Successor to xorshift128+. Quality: Excellent | Period: 2^256 - 1 | Use: General purpose, floating point
Xoshiro256** (star-star variant) - Best all-around quality.Parameters:
  • s0, s1, s2, s3 - Four 64-bit state components
Returns: “result s0_new s1_new s2_new s3_new”
# Initialize state using splitmix64
read -r s0 s1 s2 s3 <<< "$(random::splitmix64::seed_xoshiro $(random::seed64))"

# Generate values
read -r val s0 s1 s2 s3 <<< "$(random::xoshiro256ss $s0 $s1 $s2 $s3)"
echo "Random: $val"
Xoshiro256+ variant - Faster output, slightly weaker low bits.Parameters:
  • s0, s1, s2, s3 - Four 64-bit state components
Returns: “result s0_new s1_new s2_new s3_new”
read -r val s0 s1 s2 s3 <<< "$(random::xoshiro256p $s0 $s1 $s2 $s3)"

PCG (Permuted Congruential Generator)

Melissa O’Neill, 2014 - LCG with permutation output function. Quality: Excellent | Period: 2^64 | Use: General purpose, simulation Passes all known statistical tests.
PCG32 with configurable increment.Parameters:
  • state - Current state (64-bit)
  • inc - Increment value (must be odd, enforced internally)
Returns: “result new_state” (space-separated)
state=$(random::seed64)
inc=1442695040888963407  # Any odd number

read -r val state <<< "$(random::pcg32 $state $inc)"
echo "Random: $val"

# Next value
read -r val state <<< "$(random::pcg32 $state $inc)"
PCG32 with hardcoded increment - Same quality, simpler usage.Parameters:
  • state - Current state (64-bit)
Returns: “result new_state”
state=$(random::seed64)

read -r val state <<< "$(random::pcg32::fast $state)"
echo "Random: $val"

SplitMix64

Guy Steele, Doug Lea, Christine Flood - Java 8, 2014. Quality: Good | Period: 2^64 | Use: Seeding other PRNGs, fast generation
Generate next value and state.Parameters:
  • state - Current state (64-bit)
Returns: “result new_state”
state=$(random::seed64)

read -r val state <<< "$(random::splitmix64 $state)"
echo "Random: $val"
Use case: Particularly useful for expanding a single seed into multi-word PRNG state.
Expand a single 64-bit seed into four words for xoshiro256 initialization.Parameters:
  • seed - Initial 64-bit seed
Returns: “s0 s1 s2 s3” (four space-separated values)
seed=$(random::seed64)
read -r s0 s1 s2 s3 <<< "$(random::splitmix64::seed_xoshiro $seed)"

# Now use with xoshiro256
read -r val s0 s1 s2 s3 <<< "$(random::xoshiro256ss $s0 $s1 $s2 $s3)"

Mulberry32

Tommy Ettinger - Single 32-bit state with excellent avalanche properties. Quality: Good for 32-bit | Period: 2^32 | Use: Simple fast 32-bit generation
Generate next value from mulberry32 algorithm.Parameters:
  • state - Current state (32-bit)
Returns: “result new_state”
state=$(random::seed32)

read -r val state <<< "$(random::mulberry32 $state)"
echo "Random: $val"

Wyrand

Wang Yi, 2019 - Output function of the wyhash family. Quality: Excellent | Period: 2^64 | Use: Hashing, fast generation Passes BigCrush.
Generate next value from wyrand algorithm.Parameters:
  • state - Current state (64-bit)
Returns: “result new_state”
state=$(random::seed64)

read -r val state <<< "$(random::wyrand $state)"
echo "Random: $val"

WELL512

Well Equidistributed Long-period Linear - Panneton, L’Ecuyer & Matsumoto, 2006. Quality: Excellent | Period: 2^512 - 1 | Use: Simulation, games Better equidistribution than Mersenne Twister at similar speed.
Initialize WELL512 state from a single seed.Parameters:
  • seed - Initial seed (64-bit)
Returns: “0 s0 s1 … s15” (index + 16 state words)
state_str=$(random::well512::init $(random::seed64))
read -r idx s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 <<< "$state_str"
Generate next value from WELL512 algorithm.Parameters:
  • index - Current index (0-15)
  • s0s15 - 16 state words (32-bit each)
Returns: “result new_index s0 … s15”
# Initialize
state_str=$(random::well512::init $(random::seed64))
read -r idx s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 <<< "$state_str"

# Generate value
result=$(random::well512 $idx $s0 $s1 $s2 $s3 $s4 $s5 $s6 $s7 $s8 $s9 $s10 $s11 $s12 $s13 $s14 $s15)
read -r val idx s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 <<< "$result"
echo "Random: $val"

ISAAC

Indirection, Shift, Accumulate, Add, Count - Robert Jenkins, 1996. Quality: Cryptographic-adjacent | Period: 2^8295 | Use: Security-adjacent tasks
Not considered cryptographically secure by modern standards but far stronger than other algorithms here. This is a simplified 8-word demonstration; full ISAAC uses 256-word state.
Initialize simplified ISAAC state.Parameters:
  • seed - Initial seed (64-bit)
Returns: “a b c s0 s1 s2 s3 s4 s5 s6 s7” (3 accumulators + 8 state words)
state_str=$(random::isaac::init $(random::seed64))
read -r a b c s0 s1 s2 s3 s4 s5 s6 s7 <<< "$state_str"
Generate next value from simplified ISAAC.Parameters:
  • a, b, c - Internal accumulators
  • s0s7 - 8 state words
Returns: “result new_a new_b new_c s0 … s7”
# Initialize
state_str=$(random::isaac::init $(random::seed64))
read -r a b c s0 s1 s2 s3 s4 s5 s6 s7 <<< "$state_str"

# Generate value
result=$(random::isaac $a $b $c $s0 $s1 $s2 $s3 $s4 $s5 $s6 $s7)
read -r val a b c s0 s1 s2 s3 s4 s5 s6 s7 <<< "$result"
echo "Random: $val"

Algorithm comparison

AlgorithmQualityPeriodSpeedState SizeUse Case
Native ($RANDOM)Poor2^15FastBuilt-inQuick scripts
Middle SquareVery PoorVariableFast1 wordHistorical demo
LCGPoor-Moderate2^32Fast1 wordSimple sims
Xorshift32Moderate2^32-1Fast1 wordFast generation
Xorshift64Moderate2^64-1Fast1 wordFast generation
Xorshift128+Good2^128-1Fast2 wordsGeneral purpose
Xoshiro256**Excellent2^256-1Fast4 wordsRecommended
PCG32Excellent2^64Fast2 wordsSimulation
SplitMix64Good2^64Fast1 wordSeeding others
Mulberry32Good2^32Fast1 wordSimple 32-bit
WyrandExcellent2^64Very Fast1 wordHashing
WELL512Excellent2^512-1Moderate17 wordsGames
ISAACCrypto-adjacent2^8295Moderate11 wordsSecurity-adjacent

Usage examples

Simple random number generation

#!/bin/bash
source random.sh

# Using PCG32 (recommended for general use)
state=$(random::seed64)

for i in {1..10}; do
    read -r val state <<< "$(random::pcg32::fast $state)"
    echo "Random value $i: $val"
done

Dice roller with xoshiro256

#!/bin/bash
source random.sh

# Initialize xoshiro256**
read -r s0 s1 s2 s3 <<< "$(random::splitmix64::seed_xoshiro $(random::seed64))"

roll_dice() {
    local sides=$1
    read -r val s0 s1 s2 s3 <<< "$(random::xoshiro256ss $s0 $s1 $s2 $s3)"
    # Convert to range [1, sides]
    local result=$(( (val % sides) + 1 ))
    echo $result
}

echo "Rolling 2d6:"
die1=$(roll_dice 6)
die2=$(roll_dice 6)
echo "$die1 + $die2 = $((die1 + die2))"

Monte Carlo simulation

#!/bin/bash
source random.sh

# Estimate π using Monte Carlo method
state=$(random::seed64)
inside=0
total=100000

for (( i=0; i<total; i++ )); do
    read -r x state <<< "$(random::pcg32::fast $state)"
    read -r y state <<< "$(random::pcg32::fast $state)"
    
    # Normalize to [0,1]
    x_norm=$(bc -l <<< "$x / 4294967295")
    y_norm=$(bc -l <<< "$y / 4294967295")
    
    # Check if inside unit circle
    dist=$(bc -l <<< "$x_norm*$x_norm + $y_norm*$y_norm")
    (( $(bc -l <<< "$dist < 1") )) && (( inside++ ))
done

pi_estimate=$(bc -l <<< "4 * $inside / $total")
echo "π ≈ $pi_estimate"

Reproducible random sequences

#!/bin/bash
source random.sh

# Same seed = same sequence (deterministic)
fixed_seed=12345

generate_sequence() {
    local state=$1
    for i in {1..5}; do
        read -r val state <<< "$(random::pcg32::fast $state)"
        echo "$val"
    done
}

echo "First run:"
generate_sequence $fixed_seed

echo -e "\nSecond run (identical):"
generate_sequence $fixed_seed

Benchmark PRNG performance

#!/bin/bash
source random.sh
source timedate.sh

benchmark_prng() {
    local name=$1
    local iterations=10000
    
    local start=$(timedate::time::stopwatch::start)
    
    local state=$(random::seed64)
    for (( i=0; i<iterations; i++ )); do
        read -r val state <<< "$(random::pcg32::fast $state)"
    done
    
    local elapsed=$(timedate::time::stopwatch::stop $start)
    echo "$name: $elapsed ms for $iterations iterations"
}

benchmark_prng "PCG32-Fast"

Build docs developers (and LLMs) love