From bf1ba83292e767365be925c132027c67ec40fe68 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Mon, 28 Jul 2014 13:40:51 +0200 Subject: [PATCH 1/3] doc: Monty Hall simulation for std::rand A larger example for std::rand --- src/libstd/rand/mod.rs | 103 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index a9b9a907a2642..273b1d7f34300 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -71,6 +71,109 @@ use std::rand; let tuple = rand::random::<(f64, char)>(); println!("{}", tuple) ``` + +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 of 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. + +[Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem + +``` +use std::rand; +use std::rand::Rng; +use std::rand::distributions::{IndependentSample, Range}; + +struct SimulationResult { + win: bool, + switch: bool +} + +// Run a single simulation of the Monty Hall problem. +fn simulate(rng: &mut R) -> SimulationResult { + let random_door = Range::new(0u, 3); + 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(car: uint, choice: uint, rng: &mut R) -> uint { + let choices = free_doors(vec![car, choice]); + rand::sample(rng, choices.move_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: uint, open: uint) -> uint { + free_doors(vec![choice, open])[0] +} + +fn free_doors(blocked: Vec) -> Vec { + range(0u, 3).filter(|x| !blocked.contains(x)).collect() +} + +fn main() { + // The estimation will be more accuraty with more simulations + let num_simulations = 10000u; + + let mut rng = rand::task_rng(); + + let (mut switch_wins, mut switch_losses) = (0u, 0u); + let (mut keep_wins, mut keep_losses) = (0u, 0u); + + println!("Running {} simulations...", num_simulations); + for _ in range(0, num_simulations) { + let result = simulate(&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); +} +``` + */ #![experimental] From 42ca8a70d60d066367484b153c1d84de728b14cf Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Mon, 28 Jul 2014 15:04:21 +0200 Subject: [PATCH 2/3] doc: More efficient Monty Hall simulation --- src/libstd/rand/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 273b1d7f34300..013640dba5de4 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -95,12 +95,11 @@ use std::rand::distributions::{IndependentSample, Range}; struct SimulationResult { win: bool, - switch: bool + switch: bool, } // Run a single simulation of the Monty Hall problem. -fn simulate(rng: &mut R) -> SimulationResult { - let random_door = Range::new(0u, 3); +fn simulate(random_door: &Range, rng: &mut R) -> SimulationResult { let car = random_door.ind_sample(rng); // This is our initial choice @@ -121,32 +120,33 @@ fn simulate(rng: &mut R) -> SimulationResult { // 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(car: uint, choice: uint, rng: &mut R) -> uint { - let choices = free_doors(vec![car, choice]); + let choices = free_doors(&[car, choice]); rand::sample(rng, choices.move_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: uint, open: uint) -> uint { - free_doors(vec![choice, open])[0] + free_doors(&[choice, open])[0] } -fn free_doors(blocked: Vec) -> Vec { +fn free_doors(blocked: &[uint]) -> Vec { range(0u, 3).filter(|x| !blocked.contains(x)).collect() } fn main() { - // The estimation will be more accuraty with more simulations + // The estimation will be more accurate with more simulations let num_simulations = 10000u; let mut rng = rand::task_rng(); + let random_door = Range::new(0u, 3); let (mut switch_wins, mut switch_losses) = (0u, 0u); let (mut keep_wins, mut keep_losses) = (0u, 0u); println!("Running {} simulations...", num_simulations); for _ in range(0, num_simulations) { - let result = simulate(&mut rng); + let result = simulate(&random_door, &mut rng); match (result.win, result.switch) { (true, true) => switch_wins += 1, From 23b84e55e4dc0ed35192070cd442a0f5fd38a87e Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Mon, 28 Jul 2014 17:52:48 +0200 Subject: [PATCH 3/3] doc: use //! instead of /*! ... */ in std::rand --- src/libstd/rand/mod.rs | 330 ++++++++++++++++++++--------------------- 1 file changed, 163 insertions(+), 167 deletions(-) diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 013640dba5de4..40d8f80171c4e 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -8,173 +8,169 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - -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::()`. - -See the `distributions` submodule for sampling random numbers from -distributions like normal and exponential. - -# Task-local RNG - -There is built-in support for a RNG associated with each task stored -in task-local storage. This RNG can be accessed via `task_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: - -- On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. - This does not mean that `/dev/random` provides better output than - `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom - number generator (CSPRNG) based on entropy pool for random number generation, - so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. - However, this means that `/dev/urandom` can yield somewhat predictable randomness - if the entropy pool is very small, such as immediately after first booting. - If an application likely to be run soon after first booting, or on a system with very - few entropy sources, one should consider using `/dev/random` via `ReaderRng`. -- On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference - between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` - and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) - -# Examples - -```rust -use std::rand; -use std::rand::Rng; - -let mut rng = rand::task_rng(); -if rng.gen() { // random bool - println!("int: {}, uint: {}", rng.gen::(), rng.gen::()) -} -``` - -```rust -use std::rand; - -let tuple = rand::random::<(f64, char)>(); -println!("{}", tuple) -``` - -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 of 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. - -[Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem - -``` -use std::rand; -use std::rand::Rng; -use std::rand::distributions::{IndependentSample, Range}; - -struct SimulationResult { - win: bool, - switch: bool, -} - -// Run a single simulation of the Monty Hall problem. -fn simulate(random_door: &Range, 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(car: uint, choice: uint, rng: &mut R) -> uint { - let choices = free_doors(&[car, choice]); - rand::sample(rng, choices.move_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: uint, open: uint) -> uint { - free_doors(&[choice, open])[0] -} - -fn free_doors(blocked: &[uint]) -> Vec { - range(0u, 3).filter(|x| !blocked.contains(x)).collect() -} - -fn main() { - // The estimation will be more accurate with more simulations - let num_simulations = 10000u; - - let mut rng = rand::task_rng(); - let random_door = Range::new(0u, 3); - - let (mut switch_wins, mut switch_losses) = (0u, 0u); - let (mut keep_wins, mut keep_losses) = (0u, 0u); - - println!("Running {} simulations...", num_simulations); - for _ in range(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); -} -``` - -*/ +//! 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::()`. +//! +//! See the `distributions` submodule for sampling random numbers from +//! distributions like normal and exponential. +//! +//! # Task-local RNG +//! +//! There is built-in support for a RNG associated with each task stored +//! in task-local storage. This RNG can be accessed via `task_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: +//! +//! - On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. +//! This does not mean that `/dev/random` provides better output than +//! `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom +//! number generator (CSPRNG) based on entropy pool for random number generation, +//! so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. +//! However, this means that `/dev/urandom` can yield somewhat predictable randomness +//! if the entropy pool is very small, such as immediately after first booting. +//! If an application likely to be run soon after first booting, or on a system with very +//! few entropy sources, one should consider using `/dev/random` via `ReaderRng`. +//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference +//! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` +//! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) +//! +//! # Examples +//! +//! ```rust +//! use std::rand; +//! use std::rand::Rng; +//! +//! let mut rng = rand::task_rng(); +//! if rng.gen() { // random bool +//! println!("int: {}, uint: {}", rng.gen::(), rng.gen::()) +//! } +//! ``` +//! +//! ```rust +//! use std::rand; +//! +//! let tuple = rand::random::<(f64, char)>(); +//! println!("{}", tuple) +//! ``` +//! +//! 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 of 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. +//! +//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem +//! +//! ``` +//! use std::rand; +//! use std::rand::Rng; +//! use std::rand::distributions::{IndependentSample, Range}; +//! +//! struct SimulationResult { +//! win: bool, +//! switch: bool, +//! } +//! +//! // Run a single simulation of the Monty Hall problem. +//! fn simulate(random_door: &Range, 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(car: uint, choice: uint, rng: &mut R) -> uint { +//! let choices = free_doors(&[car, choice]); +//! rand::sample(rng, choices.move_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: uint, open: uint) -> uint { +//! free_doors(&[choice, open])[0] +//! } +//! +//! fn free_doors(blocked: &[uint]) -> Vec { +//! range(0u, 3).filter(|x| !blocked.contains(x)).collect() +//! } +//! +//! fn main() { +//! // The estimation will be more accurate with more simulations +//! let num_simulations = 10000u; +//! +//! let mut rng = rand::task_rng(); +//! let random_door = Range::new(0u, 3); +//! +//! let (mut switch_wins, mut switch_losses) = (0u, 0u); +//! let (mut keep_wins, mut keep_losses) = (0u, 0u); +//! +//! println!("Running {} simulations...", num_simulations); +//! for _ in range(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); +//! } +//! ``` #![experimental]