Crate rand[stability] [-] [+] [src]

Utilities for random number generation

The key functions are random() and Rng::gen(). These are polymorphic and so can be used to generate any type that implements Rand. Type inference means that often a simple call to rand::random() or rng.gen() will suffice, but sometimes an annotation is required, e.g. rand::random::<f64>().

See the distributions submodule for sampling random numbers from distributions like normal and exponential.

Thread-local RNG

There is built-in support for a RNG associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.

Cryptographic security

An application that requires an entropy source for cryptographic purposes must use OsRng, which reads randomness from the source that the operating system provides (e.g. /dev/urandom on Unixes or CryptGenRandom() on Windows). The other random number generators provided by this module are not suitable for such purposes.

Note: many Unix systems provide /dev/random as well as /dev/urandom. This module uses /dev/urandom for the following reasons:

Examples

use rand::Rng;

let mut rng = rand::thread_rng();
if rng.gen() { // random bool
    println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
}
let tuple = rand::random::<(f64, char)>();
println!("{:?}", tuple)

Monte Carlo estimation of π

For this example, imagine we have a square with sides of length 2 and a unit circle, both centered at the origin. Since the area of a unit circle is π, we have:

    (area of unit circle) / (area of square) = π / 4

So if we sample many points randomly from the square, roughly π / 4 of them should be inside the circle.

We can use the above fact to estimate the value of π: pick many points in the square at random, calculate the fraction that fall within the circle, and multiply this fraction by 4.

use rand::distributions::{IndependentSample, Range};

fn main() {
   let between = Range::new(-1f64, 1.);
   let mut rng = rand::thread_rng();

   let total = 1_000_000;
   let mut in_circle = 0;

   for _ in 0..total {
       let a = between.ind_sample(&mut rng);
       let b = between.ind_sample(&mut rng);
       if a*a + b*b <= 1. {
           in_circle += 1;
       }
   }

   // prints something close to 3.14159...
   println!("{}", 4. * (in_circle as f64) / (total as f64));
}

Monty Hall Problem

This is a simulation of the Monty Hall Problem:

Suppose you're on a game show, and you're given the choice of three doors: Behind one door is a car; behind the others, goats. You pick a door, say No. 1, and the host, who knows what's behind the doors, opens another door, say No. 3, which has a goat. He then says to you, "Do you want to pick door No. 2?" Is it to your advantage to switch your choice?

The rather unintuitive answer is that you will have a 2/3 chance of winning if you switch and a 1/3 chance of winning if you don't, so it's better to switch.

This program will simulate the game show and with large enough simulation steps it will indeed confirm that it is better to switch.

use rand::Rng;
use rand::distributions::{IndependentSample, Range};

struct SimulationResult {
    win: bool,
    switch: bool,
}

// Run a single simulation of the Monty Hall problem.
fn simulate<R: Rng>(random_door: &Range<usize>, rng: &mut R) -> SimulationResult {
    let car = random_door.ind_sample(rng);

    // This is our initial choice
    let mut choice = random_door.ind_sample(rng);

    // The game host opens a door
    let open = game_host_open(car, choice, rng);

    // Shall we switch?
    let switch = rng.gen();
    if switch {
        choice = switch_door(choice, open);
    }

    SimulationResult { win: choice == car, switch: switch }
}

// Returns the door the game host opens given our choice and knowledge of
// where the car is. The game host will never open the door with the car.
fn game_host_open<R: Rng>(car: usize, choice: usize, rng: &mut R) -> usize {
    let choices = free_doors(&[car, choice]);
    rand::sample(rng, choices.into_iter(), 1)[0]
}

// Returns the door we switch to, given our current choice and
// the open door. There will only be one valid door.
fn switch_door(choice: usize, open: usize) -> usize {
    free_doors(&[choice, open])[0]
}

fn free_doors(blocked: &[usize]) -> Vec<usize> {
    (0..3).filter(|x| !blocked.contains(x)).collect()
}

fn main() {
    // The estimation will be more accurate with more simulations
    let num_simulations = 10000;

    let mut rng = rand::thread_rng();
    let random_door = Range::new(0, 3);

    let (mut switch_wins, mut switch_losses) = (0, 0);
    let (mut keep_wins, mut keep_losses) = (0, 0);

    println!("Running {} simulations...", num_simulations);
    for _ in 0..num_simulations {
        let result = simulate(&random_door, &mut rng);

        match (result.win, result.switch) {
            (true, true) => switch_wins += 1,
            (true, false) => keep_wins += 1,
            (false, true) => switch_losses += 1,
            (false, false) => keep_losses += 1,
        }
    }

    let total_switches = switch_wins + switch_losses;
    let total_keeps = keep_wins + keep_losses;

    println!("Switched door {} times with {} wins and {} losses",
             total_switches, switch_wins, switch_losses);

    println!("Kept our choice {} times with {} wins and {} losses",
             total_keeps, keep_wins, keep_losses);

    // With a large number of simulations, the values should converge to
    // 0.667 and 0.333 respectively.
    println!("Estimated chance to win if we switch: {}",
             switch_wins as f32 / total_switches as f32);
    println!("Estimated chance to win if we don't: {}",
             keep_wins as f32 / total_keeps as f32);
}

Reexports

pub use isaac::{IsaacRng, Isaac64Rng};
pub use chacha::ChaChaRng;

Modules

chacha

The ChaCha random number generator.

distributions

Sampling from random distributions.

isaac

The ISAAC random number generator.

os

Interfaces to the operating system provided random number generators.

reader

A wrapper around any Reader to treat it as an RNG.

reseeding

A wrapper around another RNG that reseeds it after it generates a certain number of random bytes.

Structs

AsciiGenerator

Iterator which will continuously generate random ascii characters.

Closed01

A wrapper for generating floating point numbers uniformly in the closed interval [0,1] (including both endpoints).

Generator

Iterator which will generate a stream of random items.

Open01

A wrapper for generating floating point numbers uniformly in the open interval (0,1) (not including either endpoint).

OsRng

A random number generator that retrieves randomness straight from the operating system. Platform sources:

StdRng

The standard RNG. This is designed to be efficient on the current platform.

ThreadRng

The thread-local RNG.

XorShiftRng

An Xorshift[1] random number generator.

Traits

Rand

A type that can be randomly generated using an Rng.

Rng

A random number generator.

SeedableRng

A random number generator that can be explicitly seeded to produce the same stream of randomness multiple times.

Functions

random

Generates a random value using the thread-local random number generator.

sample

Randomly sample up to amount elements from an iterator.

thread_rng

Retrieve the lazily-initialized thread-local random number generator, seeded by the system. Intended to be used in method chaining style, e.g. thread_rng().gen::<i32>().

weak_rng

Create a weak random number generator with a default algorithm and seed.