|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 |
| -/*! |
12 |
| -
|
13 |
| -Utilities for random number generation |
14 |
| -
|
15 |
| -The key functions are `random()` and `Rng::gen()`. These are polymorphic |
16 |
| -and so can be used to generate any type that implements `Rand`. Type inference |
17 |
| -means that often a simple call to `rand::random()` or `rng.gen()` will |
18 |
| -suffice, but sometimes an annotation is required, e.g. `rand::random::<f64>()`. |
19 |
| -
|
20 |
| -See the `distributions` submodule for sampling random numbers from |
21 |
| -distributions like normal and exponential. |
22 |
| -
|
23 |
| -# Task-local RNG |
24 |
| -
|
25 |
| -There is built-in support for a RNG associated with each task stored |
26 |
| -in task-local storage. This RNG can be accessed via `task_rng`, or |
27 |
| -used implicitly via `random`. This RNG is normally randomly seeded |
28 |
| -from an operating-system source of randomness, e.g. `/dev/urandom` on |
29 |
| -Unix systems, and will automatically reseed itself from this source |
30 |
| -after generating 32 KiB of random data. |
31 |
| -
|
32 |
| -# Cryptographic security |
33 |
| -
|
34 |
| -An application that requires an entropy source for cryptographic purposes |
35 |
| -must use `OsRng`, which reads randomness from the source that the operating |
36 |
| -system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on Windows). |
37 |
| -The other random number generators provided by this module are not suitable |
38 |
| -for such purposes. |
39 |
| -
|
40 |
| -*Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. |
41 |
| -This module uses `/dev/urandom` for the following reasons: |
42 |
| -
|
43 |
| -- On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. |
44 |
| - This does not mean that `/dev/random` provides better output than |
45 |
| - `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom |
46 |
| - number generator (CSPRNG) based on entropy pool for random number generation, |
47 |
| - so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. |
48 |
| - However, this means that `/dev/urandom` can yield somewhat predictable randomness |
49 |
| - if the entropy pool is very small, such as immediately after first booting. |
50 |
| - If an application likely to be run soon after first booting, or on a system with very |
51 |
| - few entropy sources, one should consider using `/dev/random` via `ReaderRng`. |
52 |
| -- On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference |
53 |
| - between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` |
54 |
| - and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) |
55 |
| -
|
56 |
| -# Examples |
57 |
| -
|
58 |
| -```rust |
59 |
| -use std::rand; |
60 |
| -use std::rand::Rng; |
61 |
| -
|
62 |
| -let mut rng = rand::task_rng(); |
63 |
| -if rng.gen() { // random bool |
64 |
| - println!("int: {}, uint: {}", rng.gen::<int>(), rng.gen::<uint>()) |
65 |
| -} |
66 |
| -``` |
67 |
| -
|
68 |
| -```rust |
69 |
| -use std::rand; |
70 |
| -
|
71 |
| -let tuple = rand::random::<(f64, char)>(); |
72 |
| -println!("{}", tuple) |
73 |
| -``` |
74 |
| -*/ |
| 11 | +//! Utilities for random number generation |
| 12 | +//! |
| 13 | +//! The key functions are `random()` and `Rng::gen()`. These are polymorphic |
| 14 | +//! and so can be used to generate any type that implements `Rand`. Type inference |
| 15 | +//! means that often a simple call to `rand::random()` or `rng.gen()` will |
| 16 | +//! suffice, but sometimes an annotation is required, e.g. `rand::random::<f64>()`. |
| 17 | +//! |
| 18 | +//! See the `distributions` submodule for sampling random numbers from |
| 19 | +//! distributions like normal and exponential. |
| 20 | +//! |
| 21 | +//! # Task-local RNG |
| 22 | +//! |
| 23 | +//! There is built-in support for a RNG associated with each task stored |
| 24 | +//! in task-local storage. This RNG can be accessed via `task_rng`, or |
| 25 | +//! used implicitly via `random`. This RNG is normally randomly seeded |
| 26 | +//! from an operating-system source of randomness, e.g. `/dev/urandom` on |
| 27 | +//! Unix systems, and will automatically reseed itself from this source |
| 28 | +//! after generating 32 KiB of random data. |
| 29 | +//! |
| 30 | +//! # Cryptographic security |
| 31 | +//! |
| 32 | +//! An application that requires an entropy source for cryptographic purposes |
| 33 | +//! must use `OsRng`, which reads randomness from the source that the operating |
| 34 | +//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on Windows). |
| 35 | +//! The other random number generators provided by this module are not suitable |
| 36 | +//! for such purposes. |
| 37 | +//! |
| 38 | +//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. |
| 39 | +//! This module uses `/dev/urandom` for the following reasons: |
| 40 | +//! |
| 41 | +//! - On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. |
| 42 | +//! This does not mean that `/dev/random` provides better output than |
| 43 | +//! `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom |
| 44 | +//! number generator (CSPRNG) based on entropy pool for random number generation, |
| 45 | +//! so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. |
| 46 | +//! However, this means that `/dev/urandom` can yield somewhat predictable randomness |
| 47 | +//! if the entropy pool is very small, such as immediately after first booting. |
| 48 | +//! If an application likely to be run soon after first booting, or on a system with very |
| 49 | +//! few entropy sources, one should consider using `/dev/random` via `ReaderRng`. |
| 50 | +//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference |
| 51 | +//! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` |
| 52 | +//! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) |
| 53 | +//! |
| 54 | +//! # Examples |
| 55 | +//! |
| 56 | +//! ```rust |
| 57 | +//! use std::rand; |
| 58 | +//! use std::rand::Rng; |
| 59 | +//! |
| 60 | +//! let mut rng = rand::task_rng(); |
| 61 | +//! if rng.gen() { // random bool |
| 62 | +//! println!("int: {}, uint: {}", rng.gen::<int>(), rng.gen::<uint>()) |
| 63 | +//! } |
| 64 | +//! ``` |
| 65 | +//! |
| 66 | +//! ```rust |
| 67 | +//! use std::rand; |
| 68 | +//! |
| 69 | +//! let tuple = rand::random::<(f64, char)>(); |
| 70 | +//! println!("{}", tuple) |
| 71 | +//! ``` |
| 72 | +//! |
| 73 | +//! This is a simulation of the [Monty Hall Problem][]: |
| 74 | +//! |
| 75 | +//! > Suppose you're on a game show, and you're given the choice of three doors: |
| 76 | +//! > Behind one door is a car; behind the others, goats. You pick a door, say No. 1, |
| 77 | +//! > and the host, who knows what's behind the doors, opens another door, say No. 3, |
| 78 | +//! > which has a goat. He then says to you, "Do you want to pick door No. 2?" |
| 79 | +//! > Is it to your advantage to switch your choice? |
| 80 | +//! |
| 81 | +//! The rather unintuitive answer is that you will have a 2/3 chance of winning if |
| 82 | +//! you switch and a 1/3 chance of winning of you don't, so it's better to switch. |
| 83 | +//! |
| 84 | +//! This program will simulate the game show and with large enough simulation steps |
| 85 | +//! it will indeed confirm that it is better to switch. |
| 86 | +//! |
| 87 | +//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem |
| 88 | +//! |
| 89 | +//! ``` |
| 90 | +//! use std::rand; |
| 91 | +//! use std::rand::Rng; |
| 92 | +//! use std::rand::distributions::{IndependentSample, Range}; |
| 93 | +//! |
| 94 | +//! struct SimulationResult { |
| 95 | +//! win: bool, |
| 96 | +//! switch: bool, |
| 97 | +//! } |
| 98 | +//! |
| 99 | +//! // Run a single simulation of the Monty Hall problem. |
| 100 | +//! fn simulate<R: Rng>(random_door: &Range<uint>, rng: &mut R) -> SimulationResult { |
| 101 | +//! let car = random_door.ind_sample(rng); |
| 102 | +//! |
| 103 | +//! // This is our initial choice |
| 104 | +//! let mut choice = random_door.ind_sample(rng); |
| 105 | +//! |
| 106 | +//! // The game host opens a door |
| 107 | +//! let open = game_host_open(car, choice, rng); |
| 108 | +//! |
| 109 | +//! // Shall we switch? |
| 110 | +//! let switch = rng.gen(); |
| 111 | +//! if switch { |
| 112 | +//! choice = switch_door(choice, open); |
| 113 | +//! } |
| 114 | +//! |
| 115 | +//! SimulationResult { win: choice == car, switch: switch } |
| 116 | +//! } |
| 117 | +//! |
| 118 | +//! // Returns the door the game host opens given our choice and knowledge of |
| 119 | +//! // where the car is. The game host will never open the door with the car. |
| 120 | +//! fn game_host_open<R: Rng>(car: uint, choice: uint, rng: &mut R) -> uint { |
| 121 | +//! let choices = free_doors(&[car, choice]); |
| 122 | +//! rand::sample(rng, choices.move_iter(), 1)[0] |
| 123 | +//! } |
| 124 | +//! |
| 125 | +//! // Returns the door we switch to, given our current choice and |
| 126 | +//! // the open door. There will only be one valid door. |
| 127 | +//! fn switch_door(choice: uint, open: uint) -> uint { |
| 128 | +//! free_doors(&[choice, open])[0] |
| 129 | +//! } |
| 130 | +//! |
| 131 | +//! fn free_doors(blocked: &[uint]) -> Vec<uint> { |
| 132 | +//! range(0u, 3).filter(|x| !blocked.contains(x)).collect() |
| 133 | +//! } |
| 134 | +//! |
| 135 | +//! fn main() { |
| 136 | +//! // The estimation will be more accurate with more simulations |
| 137 | +//! let num_simulations = 10000u; |
| 138 | +//! |
| 139 | +//! let mut rng = rand::task_rng(); |
| 140 | +//! let random_door = Range::new(0u, 3); |
| 141 | +//! |
| 142 | +//! let (mut switch_wins, mut switch_losses) = (0u, 0u); |
| 143 | +//! let (mut keep_wins, mut keep_losses) = (0u, 0u); |
| 144 | +//! |
| 145 | +//! println!("Running {} simulations...", num_simulations); |
| 146 | +//! for _ in range(0, num_simulations) { |
| 147 | +//! let result = simulate(&random_door, &mut rng); |
| 148 | +//! |
| 149 | +//! match (result.win, result.switch) { |
| 150 | +//! (true, true) => switch_wins += 1, |
| 151 | +//! (true, false) => keep_wins += 1, |
| 152 | +//! (false, true) => switch_losses += 1, |
| 153 | +//! (false, false) => keep_losses += 1, |
| 154 | +//! } |
| 155 | +//! } |
| 156 | +//! |
| 157 | +//! let total_switches = switch_wins + switch_losses; |
| 158 | +//! let total_keeps = keep_wins + keep_losses; |
| 159 | +//! |
| 160 | +//! println!("Switched door {} times with {} wins and {} losses", |
| 161 | +//! total_switches, switch_wins, switch_losses); |
| 162 | +//! |
| 163 | +//! println!("Kept our choice {} times with {} wins and {} losses", |
| 164 | +//! total_keeps, keep_wins, keep_losses); |
| 165 | +//! |
| 166 | +//! // With a large number of simulations, the values should converge to |
| 167 | +//! // 0.667 and 0.333 respectively. |
| 168 | +//! println!("Estimated chance to win if we switch: {}", |
| 169 | +//! switch_wins as f32 / total_switches as f32); |
| 170 | +//! println!("Estimated chance to win if we don't: {}", |
| 171 | +//! keep_wins as f32 / total_keeps as f32); |
| 172 | +//! } |
| 173 | +//! ``` |
75 | 174 |
|
76 | 175 | #![experimental]
|
77 | 176 |
|
|
0 commit comments