Huon Wilson | 0b1a0d0 | 2013-10-01 17:16:22 | [diff] [blame] | 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT |
Graydon Hoare | 00c856c | 2012-12-04 00:48:01 | [diff] [blame] | 2 | // file at the top-level directory of this distribution and at |
| 3 | // http://rust-lang.org/COPYRIGHT. |
| 4 | // |
| 5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 8 | // option. This file may not be copied, modified, or distributed |
| 9 | // except according to those terms. |
| 10 | |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 11 | /*! |
| 12 | Random number generation. |
| 13 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 14 | The key functions are `random()` and `Rng::gen()`. These are polymorphic |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 15 | and so can be used to generate any type that implements `Rand`. Type inference |
| 16 | means that often a simple call to `rand::random()` or `rng.gen()` will |
Daniel Micay | c9d4ad0 | 2013-09-26 06:26:09 | [diff] [blame] | 17 | suffice, but sometimes an annotation is required, e.g. `rand::random::<f64>()`. |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 18 | |
Huon Wilson | 1eb5efc | 2013-04-28 14:18:53 | [diff] [blame] | 19 | See the `distributions` submodule for sampling random numbers from |
| 20 | distributions like normal and exponential. |
| 21 | |
Huon Wilson | 9886979 | 2013-10-01 17:17:57 | [diff] [blame] | 22 | # Task-local RNG |
| 23 | |
| 24 | There is built-in support for a RNG associated with each task stored |
| 25 | in task-local storage. This RNG can be accessed via `task_rng`, or |
| 26 | used implicitly via `random`. This RNG is normally randomly seeded |
| 27 | from an operating-system source of randomness, e.g. `/dev/urandom` on |
| 28 | Unix systems, and will automatically reseed itself from this source |
| 29 | after generating 32 KiB of random data. |
| 30 | |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 31 | # Examples |
Daniel Micay | 0d5fdce | 2013-05-27 13:49:54 | [diff] [blame] | 32 | |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 33 | ```rust |
korenchkin | 3cb3d75 | 2013-07-10 13:30:14 | [diff] [blame] | 34 | use std::rand; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 35 | use std::rand::Rng; |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 36 | |
| 37 | fn main() { |
John Clements | be22fdd | 2013-05-17 18:23:53 | [diff] [blame] | 38 | let mut rng = rand::rng(); |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 39 | if rng.gen() { // bool |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 40 | println!("int: {}, uint: {}", rng.gen::<int>(), rng.gen::<uint>()) |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 41 | } |
| 42 | } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 43 | ``` |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 44 | |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 45 | ```rust |
korenchkin | 3cb3d75 | 2013-07-10 13:30:14 | [diff] [blame] | 46 | use std::rand; |
| 47 | |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 48 | fn main () { |
| 49 | let tuple_ptr = rand::random::<~(f64, char)>(); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 50 | println!(tuple_ptr) |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 51 | } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 52 | ``` |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 53 | */ |
| 54 | |
Brian Anderson | 34d376f | 2013-10-17 01:34:01 | [diff] [blame] | 55 | use mem::size_of; |
Daniel Micay | e1a26ad | 2013-10-15 04:37:32 | [diff] [blame] | 56 | use unstable::raw::Slice; |
Patrick Walton | 206ab89 | 2013-05-25 02:35:29 | [diff] [blame] | 57 | use cast; |
Patrick Walton | e015bee | 2013-06-18 16:39:16 | [diff] [blame] | 58 | use container::Container; |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 59 | use iter::{Iterator, range}; |
Patrick Walton | 206ab89 | 2013-05-25 02:35:29 | [diff] [blame] | 60 | use local_data; |
Patrick Walton | 2db3abd | 2013-01-09 03:37:25 | [diff] [blame] | 61 | use prelude::*; |
Patrick Walton | 57c5999 | 2012-12-23 22:41:37 | [diff] [blame] | 62 | use str; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 63 | use u64; |
Patrick Walton | 57c5999 | 2012-12-23 22:41:37 | [diff] [blame] | 64 | use vec; |
| 65 | |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 66 | pub use self::isaac::{IsaacRng, Isaac64Rng}; |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 67 | pub use self::os::OSRng; |
Huon Wilson | 72bf201 | 2013-09-21 11:32:57 | [diff] [blame] | 68 | |
Huon Wilson | 1eb5efc | 2013-04-28 14:18:53 | [diff] [blame] | 69 | pub mod distributions; |
Huon Wilson | 72bf201 | 2013-09-21 11:32:57 | [diff] [blame] | 70 | pub mod isaac; |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 71 | pub mod os; |
| 72 | pub mod reader; |
Huon Wilson | 0223cf6 | 2013-09-29 06:49:11 | [diff] [blame] | 73 | pub mod reseeding; |
Huon Wilson | 0b1a0d0 | 2013-10-01 17:16:22 | [diff] [blame] | 74 | mod rand_impls; |
Huon Wilson | 1eb5efc | 2013-04-28 14:18:53 | [diff] [blame] | 75 | |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 76 | /// A type that can be randomly generated using an Rng |
Zack Corr | abd29e5 | 2013-02-05 12:56:40 | [diff] [blame] | 77 | pub trait Rand { |
Alex Crichton | 007651c | 2013-05-28 21:35:52 | [diff] [blame] | 78 | /// Generates a random instance of this type using the specified source of |
| 79 | /// randomness |
Patrick Walton | b2d1ac1 | 2013-05-03 06:09:50 | [diff] [blame] | 80 | fn rand<R: Rng>(rng: &mut R) -> Self; |
Zack Corr | abd29e5 | 2013-02-05 12:56:40 | [diff] [blame] | 81 | } |
| 82 | |
Gareth Daniel Smith | be01416 | 2012-07-04 21:53:12 | [diff] [blame] | 83 | /// A value with a particular weight compared to other values |
Erick Tryzelaar | e4d4a14 | 2013-01-22 16:12:52 | [diff] [blame] | 84 | pub struct Weighted<T> { |
Alex Crichton | 007651c | 2013-05-28 21:35:52 | [diff] [blame] | 85 | /// The numerical weight of this item |
Erick Tryzelaar | e4d4a14 | 2013-01-22 16:12:52 | [diff] [blame] | 86 | weight: uint, |
Alex Crichton | 007651c | 2013-05-28 21:35:52 | [diff] [blame] | 87 | /// The actual item which is being weighted |
Erick Tryzelaar | e4d4a14 | 2013-01-22 16:12:52 | [diff] [blame] | 88 | item: T, |
| 89 | } |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 90 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 91 | /// A random number generator |
| 92 | pub trait Rng { |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 93 | /// Return the next random u32. This rarely needs to be called |
| 94 | /// directly, prefer `r.gen()` to `r.next_u32()`. |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 95 | /// |
Huon Wilson | 62feded | 2013-10-08 22:56:57 | [diff] [blame] | 96 | // FIXME #7771: Should be implemented in terms of next_u64 |
| 97 | fn next_u32(&mut self) -> u32; |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 98 | |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 99 | /// Return the next random u64. This rarely needs to be called |
| 100 | /// directly, prefer `r.gen()` to `r.next_u64()`. |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 101 | /// |
| 102 | /// By default this is implemented in terms of `next_u32`. An |
| 103 | /// implementation of this trait must provide at least one of |
| 104 | /// these two methods. |
| 105 | fn next_u64(&mut self) -> u64 { |
| 106 | (self.next_u32() as u64 << 32) | (self.next_u32() as u64) |
| 107 | } |
Robert Knight | 11b3d76 | 2013-08-13 11:44:16 | [diff] [blame] | 108 | |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 109 | /// Fill `dest` with random data. |
| 110 | /// |
| 111 | /// This has a default implementation in terms of `next_u64` and |
| 112 | /// `next_u32`, but should be overriden by implementations that |
| 113 | /// offer a more efficient solution than just calling those |
| 114 | /// methods repeatedly. |
| 115 | /// |
| 116 | /// This method does *not* have a requirement to bear any fixed |
| 117 | /// relationship to the other methods, for example, it does *not* |
| 118 | /// have to result in the same output as progressively filling |
| 119 | /// `dest` with `self.gen::<u8>()`, and any such behaviour should |
| 120 | /// not be relied upon. |
| 121 | /// |
| 122 | /// This method should guarantee that `dest` is entirely filled |
| 123 | /// with new data, and may fail if this is impossible |
| 124 | /// (e.g. reading past the end of a file that is being used as the |
| 125 | /// source of randomness). |
| 126 | /// |
| 127 | /// # Example |
| 128 | /// |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 129 | /// ```rust |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 130 | /// use std::rand::{task_rng, Rng}; |
| 131 | /// |
| 132 | /// fn main() { |
| 133 | /// let mut v = [0u8, .. 13579]; |
| 134 | /// task_rng().fill_bytes(v); |
Huon Wilson | 9886979 | 2013-10-01 17:17:57 | [diff] [blame] | 135 | /// println!("{:?}", v); |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 136 | /// } |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 137 | /// ``` |
Daniel Micay | e1a26ad | 2013-10-15 04:37:32 | [diff] [blame] | 138 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 139 | let mut slice: Slice<u64> = unsafe { cast::transmute_copy(&dest) }; |
| 140 | slice.len /= size_of::<u64>(); |
| 141 | let as_u64: &mut [u64] = unsafe { cast::transmute(slice) }; |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 142 | for dest in as_u64.mut_iter() { |
| 143 | *dest = self.next_u64(); |
| 144 | } |
| 145 | |
| 146 | // the above will have filled up the vector as much as |
| 147 | // possible in multiples of 8 bytes. |
| 148 | let mut remaining = dest.len() % 8; |
| 149 | |
| 150 | // space for a u32 |
| 151 | if remaining >= 4 { |
Daniel Micay | e1a26ad | 2013-10-15 04:37:32 | [diff] [blame] | 152 | let mut slice: Slice<u32> = unsafe { cast::transmute_copy(&dest) }; |
| 153 | slice.len /= size_of::<u32>(); |
| 154 | let as_u32: &mut [u32] = unsafe { cast::transmute(slice) }; |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 155 | as_u32[as_u32.len() - 1] = self.next_u32(); |
| 156 | remaining -= 4; |
| 157 | } |
| 158 | // exactly filled |
| 159 | if remaining == 0 { return } |
| 160 | |
| 161 | // now we know we've either got 1, 2 or 3 spots to go, |
| 162 | // i.e. exactly one u32 is enough. |
| 163 | let rand = self.next_u32(); |
| 164 | let remaining_index = dest.len() - remaining; |
| 165 | match dest.mut_slice_from(remaining_index) { |
| 166 | [ref mut a] => { |
| 167 | *a = rand as u8; |
| 168 | } |
| 169 | [ref mut a, ref mut b] => { |
| 170 | *a = rand as u8; |
| 171 | *b = (rand >> 8) as u8; |
| 172 | } |
| 173 | [ref mut a, ref mut b, ref mut c] => { |
| 174 | *a = rand as u8; |
| 175 | *b = (rand >> 8) as u8; |
| 176 | *c = (rand >> 16) as u8; |
| 177 | } |
Alex Crichton | daf5f5a | 2013-10-21 20:08:31 | [diff] [blame^] | 178 | _ => fail!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3") |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 179 | } |
| 180 | } |
Patrick Walton | b1c6998 | 2013-03-12 20:00:50 | [diff] [blame] | 181 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 182 | /// Return a random value of a Rand type. |
| 183 | /// |
| 184 | /// # Example |
| 185 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 186 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 187 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 188 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 189 | /// |
| 190 | /// fn main() { |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 191 | /// let mut rng = rand::task_rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 192 | /// let x: uint = rng.gen(); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 193 | /// println!("{}", x); |
Daniel Micay | c9d4ad0 | 2013-09-26 06:26:09 | [diff] [blame] | 194 | /// println!("{:?}", rng.gen::<(f64, bool)>()); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 195 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 196 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 197 | #[inline(always)] |
Patrick Walton | b2d1ac1 | 2013-05-03 06:09:50 | [diff] [blame] | 198 | fn gen<T: Rand>(&mut self) -> T { |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 199 | Rand::rand(self) |
Zack Corr | abd29e5 | 2013-02-05 12:56:40 | [diff] [blame] | 200 | } |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 201 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 202 | /// Return a random vector of the specified length. |
| 203 | /// |
| 204 | /// # Example |
| 205 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 206 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 207 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 208 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 209 | /// |
| 210 | /// fn main() { |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 211 | /// let mut rng = rand::task_rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 212 | /// let x: ~[uint] = rng.gen_vec(10); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 213 | /// println!("{:?}", x); |
Daniel Micay | c9d4ad0 | 2013-09-26 06:26:09 | [diff] [blame] | 214 | /// println!("{:?}", rng.gen_vec::<(f64, bool)>(5)); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 215 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 216 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 217 | fn gen_vec<T: Rand>(&mut self, len: uint) -> ~[T] { |
| 218 | vec::from_fn(len, |_| self.gen()) |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 219 | } |
| 220 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 221 | /// Generate a random primitive integer in the range [`low`, |
| 222 | /// `high`). Fails if `low >= high`. |
| 223 | /// |
| 224 | /// This gives a uniform distribution (assuming this RNG is itself |
| 225 | /// uniform), even for edge cases like `gen_integer_range(0u8, |
| 226 | /// 170)`, which a naive modulo operation would return numbers |
| 227 | /// less than 85 with double the probability to those greater than |
| 228 | /// 85. |
| 229 | /// |
| 230 | /// # Example |
| 231 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 232 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 233 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 234 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 235 | /// |
| 236 | /// fn main() { |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 237 | /// let mut rng = rand::task_rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 238 | /// let n: uint = rng.gen_integer_range(0u, 10); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 239 | /// println!("{}", n); |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 240 | /// let m: int = rng.gen_integer_range(-40, 400); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 241 | /// println!("{}", m); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 242 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 243 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 244 | fn gen_integer_range<T: Rand + Int>(&mut self, low: T, high: T) -> T { |
| 245 | assert!(low < high, "RNG.gen_integer_range called with low >= high"); |
Erick Tryzelaar | d9d1dfc | 2013-09-15 16:50:17 | [diff] [blame] | 246 | let range = (high - low).to_u64().unwrap(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 247 | let accept_zone = u64::max_value - u64::max_value % range; |
| 248 | loop { |
| 249 | let rand = self.gen::<u64>(); |
| 250 | if rand < accept_zone { |
Erick Tryzelaar | d9d1dfc | 2013-09-15 16:50:17 | [diff] [blame] | 251 | return low + NumCast::from(rand % range).unwrap(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 252 | } |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 253 | } |
| 254 | } |
| 255 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 256 | /// Return a bool with a 1 in n chance of true |
| 257 | /// |
| 258 | /// # Example |
| 259 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 260 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 261 | /// use std::rand; |
| 262 | /// use std::rand::Rng; |
| 263 | /// |
| 264 | /// fn main() { |
| 265 | /// let mut rng = rand::rng(); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 266 | /// println!("{:b}", rng.gen_weighted_bool(3)); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 267 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 268 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 269 | fn gen_weighted_bool(&mut self, n: uint) -> bool { |
| 270 | n == 0 || self.gen_integer_range(0, n) == 0 |
| 271 | } |
| 272 | |
| 273 | /// Return a random string of the specified length composed of |
| 274 | /// A-Z,a-z,0-9. |
| 275 | /// |
| 276 | /// # Example |
| 277 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 278 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 279 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 280 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 281 | /// |
| 282 | /// fn main() { |
| 283 | /// println(rand::task_rng().gen_ascii_str(10)); |
| 284 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 285 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 286 | fn gen_ascii_str(&mut self, len: uint) -> ~str { |
| 287 | static GEN_ASCII_STR_CHARSET: &'static [u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ\ |
| 288 | abcdefghijklmnopqrstuvwxyz\ |
| 289 | 0123456789"); |
| 290 | let mut s = str::with_capacity(len); |
| 291 | for _ in range(0, len) { |
| 292 | s.push_char(self.choose(GEN_ASCII_STR_CHARSET) as char) |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 293 | } |
Luqman Aden | 5912b14 | 2013-02-15 08:51:28 | [diff] [blame] | 294 | s |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 295 | } |
| 296 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 297 | /// Choose an item randomly, failing if `values` is empty. |
| 298 | fn choose<T: Clone>(&mut self, values: &[T]) -> T { |
| 299 | self.choose_option(values).expect("Rng.choose: `values` is empty").clone() |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 300 | } |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 301 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 302 | /// Choose `Some(&item)` randomly, returning `None` if values is |
| 303 | /// empty. |
| 304 | /// |
| 305 | /// # Example |
| 306 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 307 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 308 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 309 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 310 | /// |
| 311 | /// fn main() { |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 312 | /// println!("{:?}", rand::task_rng().choose_option([1,2,4,8,16,32])); |
| 313 | /// println!("{:?}", rand::task_rng().choose_option([])); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 314 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 315 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 316 | fn choose_option<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 317 | if values.is_empty() { |
Brian Anderson | 8337fa1 | 2012-08-20 19:23:37 | [diff] [blame] | 318 | None |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 319 | } else { |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 320 | Some(&values[self.gen_integer_range(0u, values.len())]) |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 321 | } |
| 322 | } |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 323 | |
| 324 | /// Choose an item respecting the relative weights, failing if the sum of |
| 325 | /// the weights is 0 |
| 326 | /// |
| 327 | /// # Example |
| 328 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 329 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 330 | /// use std::rand; |
| 331 | /// use std::rand::Rng; |
| 332 | /// |
| 333 | /// fn main() { |
| 334 | /// let mut rng = rand::rng(); |
| 335 | /// let x = [rand::Weighted {weight: 4, item: 'a'}, |
| 336 | /// rand::Weighted {weight: 2, item: 'b'}, |
| 337 | /// rand::Weighted {weight: 2, item: 'c'}]; |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 338 | /// println!("{}", rng.choose_weighted(x)); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 339 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 340 | /// ``` |
Patrick Walton | e20549f | 2013-07-10 21:43:25 | [diff] [blame] | 341 | fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T { |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 342 | self.choose_weighted_option(v).expect("Rng.choose_weighted: total weight is 0") |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 343 | } |
| 344 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 345 | /// Choose Some(item) respecting the relative weights, returning none if |
| 346 | /// the sum of the weights is 0 |
| 347 | /// |
| 348 | /// # Example |
| 349 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 350 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 351 | /// use std::rand; |
| 352 | /// use std::rand::Rng; |
| 353 | /// |
| 354 | /// fn main() { |
| 355 | /// let mut rng = rand::rng(); |
| 356 | /// let x = [rand::Weighted {weight: 4, item: 'a'}, |
| 357 | /// rand::Weighted {weight: 2, item: 'b'}, |
| 358 | /// rand::Weighted {weight: 2, item: 'c'}]; |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 359 | /// println!("{:?}", rng.choose_weighted_option(x)); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 360 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 361 | /// ``` |
Patrick Walton | 99b33f7 | 2013-07-02 19:47:32 | [diff] [blame] | 362 | fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>]) |
| 363 | -> Option<T> { |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 364 | let mut total = 0u; |
Daniel Micay | 10089455 | 2013-08-03 16:45:23 | [diff] [blame] | 365 | for item in v.iter() { |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 366 | total += item.weight; |
| 367 | } |
| 368 | if total == 0u { |
Brian Anderson | 8337fa1 | 2012-08-20 19:23:37 | [diff] [blame] | 369 | return None; |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 370 | } |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 371 | let chosen = self.gen_integer_range(0u, total); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 372 | let mut so_far = 0u; |
Daniel Micay | 10089455 | 2013-08-03 16:45:23 | [diff] [blame] | 373 | for item in v.iter() { |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 374 | so_far += item.weight; |
| 375 | if so_far > chosen { |
Patrick Walton | 99b33f7 | 2013-07-02 19:47:32 | [diff] [blame] | 376 | return Some(item.item.clone()); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 377 | } |
| 378 | } |
Chris Morgan | e2807a4 | 2013-09-19 05:04:03 | [diff] [blame] | 379 | unreachable!(); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 380 | } |
| 381 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 382 | /// Return a vec containing copies of the items, in order, where |
| 383 | /// the weight of the item determines how many copies there are |
| 384 | /// |
| 385 | /// # Example |
| 386 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 387 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 388 | /// use std::rand; |
| 389 | /// use std::rand::Rng; |
| 390 | /// |
| 391 | /// fn main() { |
| 392 | /// let mut rng = rand::rng(); |
| 393 | /// let x = [rand::Weighted {weight: 4, item: 'a'}, |
| 394 | /// rand::Weighted {weight: 2, item: 'b'}, |
| 395 | /// rand::Weighted {weight: 2, item: 'c'}]; |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 396 | /// println!("{}", rng.weighted_vec(x)); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 397 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 398 | /// ``` |
Patrick Walton | 99b33f7 | 2013-07-02 19:47:32 | [diff] [blame] | 399 | fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] { |
Michael Sullivan | 98e161f | 2012-06-29 23:26:56 | [diff] [blame] | 400 | let mut r = ~[]; |
Daniel Micay | 10089455 | 2013-08-03 16:45:23 | [diff] [blame] | 401 | for item in v.iter() { |
| 402 | for _ in range(0u, item.weight) { |
Patrick Walton | 99b33f7 | 2013-07-02 19:47:32 | [diff] [blame] | 403 | r.push(item.item.clone()); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 404 | } |
| 405 | } |
Luqman Aden | 5912b14 | 2013-02-15 08:51:28 | [diff] [blame] | 406 | r |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 407 | } |
| 408 | |
Gareth Daniel Smith | be01416 | 2012-07-04 21:53:12 | [diff] [blame] | 409 | /// Shuffle a vec |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 410 | /// |
| 411 | /// # Example |
| 412 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 413 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 414 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 415 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 416 | /// |
| 417 | /// fn main() { |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 418 | /// println!("{:?}", rand::task_rng().shuffle(~[1,2,3])); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 419 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 420 | /// ``` |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 421 | fn shuffle<T>(&mut self, values: ~[T]) -> ~[T] { |
| 422 | let mut v = values; |
| 423 | self.shuffle_mut(v); |
| 424 | v |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 425 | } |
| 426 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 427 | /// Shuffle a mutable vector in place. |
| 428 | /// |
| 429 | /// # Example |
| 430 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 431 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 432 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 433 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 434 | /// |
| 435 | /// fn main() { |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 436 | /// let mut rng = rand::task_rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 437 | /// let mut y = [1,2,3]; |
| 438 | /// rng.shuffle_mut(y); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 439 | /// println!("{:?}", y); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 440 | /// rng.shuffle_mut(y); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 441 | /// println!("{:?}", y); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 442 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 443 | /// ``` |
Patrick Walton | b2d1ac1 | 2013-05-03 06:09:50 | [diff] [blame] | 444 | fn shuffle_mut<T>(&mut self, values: &mut [T]) { |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 445 | let mut i = values.len(); |
| 446 | while i >= 2u { |
| 447 | // invariant: elements with index >= i have been locked in place. |
| 448 | i -= 1u; |
| 449 | // lock element i in place. |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 450 | values.swap(i, self.gen_integer_range(0u, i + 1u)); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 451 | } |
| 452 | } |
Robert Knight | 11b3d76 | 2013-08-13 11:44:16 | [diff] [blame] | 453 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 454 | /// Randomly sample up to `n` elements from an iterator. |
| 455 | /// |
| 456 | /// # Example |
| 457 | /// |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 458 | /// ```rust |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 459 | /// use std::rand; |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 460 | /// use std::rand::Rng; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 461 | /// |
| 462 | /// fn main() { |
flo-l | bf6b198 | 2013-10-04 14:38:05 | [diff] [blame] | 463 | /// let mut rng = rand::task_rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 464 | /// let sample = rng.sample(range(1, 100), 5); |
Alex Crichton | 409182d | 2013-09-25 05:16:43 | [diff] [blame] | 465 | /// println!("{:?}", sample); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 466 | /// } |
Alex Crichton | 3585c64 | 2013-09-24 00:20:36 | [diff] [blame] | 467 | /// ``` |
Robert Knight | 11b3d76 | 2013-08-13 11:44:16 | [diff] [blame] | 468 | fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A] { |
| 469 | let mut reservoir : ~[A] = vec::with_capacity(n); |
| 470 | for (i, elem) in iter.enumerate() { |
| 471 | if i < n { |
| 472 | reservoir.push(elem); |
Alex Crichton | 4f67dcb | 2013-10-01 21:31:03 | [diff] [blame] | 473 | continue |
Robert Knight | 11b3d76 | 2013-08-13 11:44:16 | [diff] [blame] | 474 | } |
| 475 | |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 476 | let k = self.gen_integer_range(0, i + 1); |
Robert Knight | 11b3d76 | 2013-08-13 11:44:16 | [diff] [blame] | 477 | if k < reservoir.len() { |
| 478 | reservoir[k] = elem |
| 479 | } |
| 480 | } |
| 481 | reservoir |
| 482 | } |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 483 | } |
Roy Frostig | 5b6e714 | 2010-07-26 04:45:09 | [diff] [blame] | 484 | |
Huon Wilson | 92725ae | 2013-09-29 15:29:28 | [diff] [blame] | 485 | /// A random number generator that can be explicitly seeded to produce |
| 486 | /// the same stream of randomness multiple times. |
| 487 | pub trait SeedableRng<Seed>: Rng { |
| 488 | /// Reseed an RNG with the given seed. |
| 489 | /// |
| 490 | /// # Example |
| 491 | /// |
| 492 | /// ```rust |
| 493 | /// use std::rand; |
| 494 | /// use std::rand::Rng; |
| 495 | /// |
| 496 | /// fn main() { |
Huon Wilson | 9886979 | 2013-10-01 17:17:57 | [diff] [blame] | 497 | /// let mut rng: rand::StdRng = rand::SeedableRng::from_seed(&[1, 2, 3, 4]); |
Huon Wilson | 92725ae | 2013-09-29 15:29:28 | [diff] [blame] | 498 | /// println!("{}", rng.gen::<f64>()); |
| 499 | /// rng.reseed([5, 6, 7, 8]); |
| 500 | /// println!("{}", rng.gen::<f64>()); |
| 501 | /// } |
| 502 | /// ``` |
| 503 | fn reseed(&mut self, Seed); |
| 504 | |
| 505 | /// Create a new RNG with the given seed. |
| 506 | /// |
| 507 | /// # Example |
| 508 | /// |
| 509 | /// ```rust |
| 510 | /// use std::rand; |
| 511 | /// use std::rand::Rng; |
| 512 | /// |
| 513 | /// fn main() { |
Huon Wilson | 9886979 | 2013-10-01 17:17:57 | [diff] [blame] | 514 | /// let mut rng: rand::StdRng = rand::SeedableRng::from_seed(&[1, 2, 3, 4]); |
Huon Wilson | 92725ae | 2013-09-29 15:29:28 | [diff] [blame] | 515 | /// println!("{}", rng.gen::<f64>()); |
| 516 | /// } |
| 517 | /// ``` |
| 518 | fn from_seed(seed: Seed) -> Self; |
| 519 | } |
| 520 | |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 521 | /// Create a random number generator with a default algorithm and seed. |
Jordi Boggiano | 3db9dc1 | 2013-08-06 20:13:26 | [diff] [blame] | 522 | /// |
| 523 | /// It returns the cryptographically-safest `Rng` algorithm currently |
| 524 | /// available in Rust. If you require a specifically seeded `Rng` for |
| 525 | /// consistency over time you should pick one algorithm and create the |
| 526 | /// `Rng` yourself. |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 527 | /// |
| 528 | /// This is a very expensive operation as it has to read randomness |
| 529 | /// from the operating system and use this in an expensive seeding |
Huon Wilson | a836f13 | 2013-10-08 14:54:21 | [diff] [blame] | 530 | /// operation. If one does not require high performance generation of |
| 531 | /// random numbers, `task_rng` and/or `random` may be more |
| 532 | /// appropriate. |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 533 | pub fn rng() -> StdRng { |
| 534 | StdRng::new() |
| 535 | } |
| 536 | |
| 537 | /// The standard RNG. This is designed to be efficient on the current |
| 538 | /// platform. |
| 539 | #[cfg(not(target_word_size="64"))] |
| 540 | pub struct StdRng { priv rng: IsaacRng } |
| 541 | |
| 542 | /// The standard RNG. This is designed to be efficient on the current |
| 543 | /// platform. |
| 544 | #[cfg(target_word_size="64")] |
| 545 | pub struct StdRng { priv rng: Isaac64Rng } |
| 546 | |
| 547 | impl StdRng { |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 548 | /// Create a randomly seeded instance of `StdRng`. This reads |
| 549 | /// randomness from the OS to seed the PRNG. |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 550 | #[cfg(not(target_word_size="64"))] |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 551 | pub fn new() -> StdRng { |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 552 | StdRng { rng: IsaacRng::new() } |
| 553 | } |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 554 | /// Create a randomly seeded instance of `StdRng`. This reads |
| 555 | /// randomness from the OS to seed the PRNG. |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 556 | #[cfg(target_word_size="64")] |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 557 | pub fn new() -> StdRng { |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 558 | StdRng { rng: Isaac64Rng::new() } |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | impl Rng for StdRng { |
| 563 | #[inline] |
| 564 | fn next_u32(&mut self) -> u32 { |
| 565 | self.rng.next_u32() |
| 566 | } |
| 567 | |
| 568 | #[inline] |
| 569 | fn next_u64(&mut self) -> u64 { |
| 570 | self.rng.next_u64() |
| 571 | } |
Ben Striegel | 43d43ad | 2013-02-28 00:13:53 | [diff] [blame] | 572 | } |
| 573 | |
Huon Wilson | 92725ae | 2013-09-29 15:29:28 | [diff] [blame] | 574 | impl<'self> SeedableRng<&'self [uint]> for StdRng { |
| 575 | fn reseed(&mut self, seed: &'self [uint]) { |
| 576 | // the internal RNG can just be seeded from the above |
| 577 | // randomness. |
| 578 | self.rng.reseed(unsafe {cast::transmute(seed)}) |
| 579 | } |
| 580 | |
| 581 | fn from_seed(seed: &'self [uint]) -> StdRng { |
| 582 | StdRng { rng: SeedableRng::from_seed(unsafe {cast::transmute(seed)}) } |
| 583 | } |
| 584 | } |
| 585 | |
Jordi Boggiano | 403c52d | 2013-08-06 20:14:32 | [diff] [blame] | 586 | /// Create a weak random number generator with a default algorithm and seed. |
| 587 | /// |
Huon Wilson | abe94f9 | 2013-08-16 05:41:28 | [diff] [blame] | 588 | /// It returns the fastest `Rng` algorithm currently available in Rust without |
Jordi Boggiano | 403c52d | 2013-08-06 20:14:32 | [diff] [blame] | 589 | /// consideration for cryptography or security. If you require a specifically |
| 590 | /// seeded `Rng` for consistency over time you should pick one algorithm and |
| 591 | /// create the `Rng` yourself. |
Huon Wilson | a836f13 | 2013-10-08 14:54:21 | [diff] [blame] | 592 | /// |
| 593 | /// This will read randomness from the operating system to seed the |
| 594 | /// generator. |
Jordi Boggiano | 403c52d | 2013-08-06 20:14:32 | [diff] [blame] | 595 | pub fn weak_rng() -> XorShiftRng { |
| 596 | XorShiftRng::new() |
| 597 | } |
| 598 | |
Huon Wilson | d4b934b | 2013-04-26 13:53:29 | [diff] [blame] | 599 | /// An [Xorshift random number |
Jordi Boggiano | 3db9dc1 | 2013-08-06 20:13:26 | [diff] [blame] | 600 | /// generator](http://en.wikipedia.org/wiki/Xorshift). |
| 601 | /// |
| 602 | /// The Xorshift algorithm is not suitable for cryptographic purposes |
| 603 | /// but is very fast. If you do not know for sure that it fits your |
| 604 | /// requirements, use a more secure one such as `IsaacRng`. |
Huon Wilson | 30266a7 | 2013-04-26 13:23:49 | [diff] [blame] | 605 | pub struct XorShiftRng { |
Patrick Walton | b2d1ac1 | 2013-05-03 06:09:50 | [diff] [blame] | 606 | priv x: u32, |
| 607 | priv y: u32, |
| 608 | priv z: u32, |
| 609 | priv w: u32, |
Roy Frostig | 5b6e714 | 2010-07-26 04:45:09 | [diff] [blame] | 610 | } |
Brian Anderson | 6e27b27 | 2012-01-18 03:05:07 | [diff] [blame] | 611 | |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 612 | impl Rng for XorShiftRng { |
Huon Wilson | d4b934b | 2013-04-26 13:53:29 | [diff] [blame] | 613 | #[inline] |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 614 | fn next_u32(&mut self) -> u32 { |
Eric Holk | ad292a8 | 2012-05-30 23:31:16 | [diff] [blame] | 615 | let x = self.x; |
Alex Crichton | 13537d2 | 2013-04-12 05:10:01 | [diff] [blame] | 616 | let t = x ^ (x << 11); |
Eric Holk | ad292a8 | 2012-05-30 23:31:16 | [diff] [blame] | 617 | self.x = self.y; |
| 618 | self.y = self.z; |
| 619 | self.z = self.w; |
| 620 | let w = self.w; |
| 621 | self.w = w ^ (w >> 19) ^ (t ^ (t >> 8)); |
| 622 | self.w |
| 623 | } |
| 624 | } |
| 625 | |
Huon Wilson | 92725ae | 2013-09-29 15:29:28 | [diff] [blame] | 626 | impl SeedableRng<[u32, .. 4]> for XorShiftRng { |
| 627 | /// Reseed an XorShiftRng. This will fail if `seed` is entirely 0. |
| 628 | fn reseed(&mut self, seed: [u32, .. 4]) { |
| 629 | assert!(!seed.iter().all(|&x| x == 0), |
| 630 | "XorShiftRng.reseed called with an all zero seed."); |
| 631 | |
| 632 | self.x = seed[0]; |
| 633 | self.y = seed[1]; |
| 634 | self.z = seed[2]; |
| 635 | self.w = seed[3]; |
| 636 | } |
| 637 | |
| 638 | /// Create a new XorShiftRng. This will fail if `seed` is entirely 0. |
| 639 | fn from_seed(seed: [u32, .. 4]) -> XorShiftRng { |
| 640 | assert!(!seed.iter().all(|&x| x == 0), |
| 641 | "XorShiftRng::from_seed called with an all zero seed."); |
| 642 | |
| 643 | XorShiftRng { |
| 644 | x: seed[0], |
| 645 | y: seed[1], |
| 646 | z: seed[2], |
| 647 | w: seed[3] |
| 648 | } |
| 649 | } |
| 650 | } |
| 651 | |
Patrick Walton | 5fb2546 | 2013-05-31 22:17:22 | [diff] [blame] | 652 | impl XorShiftRng { |
Kevin Ballard | e7b8524 | 2013-08-16 19:11:34 | [diff] [blame] | 653 | /// Create an xor shift random number generator with a random seed. |
Patrick Walton | 5fb2546 | 2013-05-31 22:17:22 | [diff] [blame] | 654 | pub fn new() -> XorShiftRng { |
Kevin Ballard | e7b8524 | 2013-08-16 19:11:34 | [diff] [blame] | 655 | let mut s = [0u8, ..16]; |
| 656 | loop { |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 657 | let mut r = OSRng::new(); |
| 658 | r.fill_bytes(s); |
| 659 | |
Kevin Ballard | e7b8524 | 2013-08-16 19:11:34 | [diff] [blame] | 660 | if !s.iter().all(|x| *x == 0) { |
| 661 | break; |
| 662 | } |
| 663 | } |
Huon Wilson | a836f13 | 2013-10-08 14:54:21 | [diff] [blame] | 664 | let s: [u32, ..4] = unsafe { cast::transmute(s) }; |
| 665 | SeedableRng::from_seed(s) |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 666 | } |
Huon Wilson | 30266a7 | 2013-04-26 13:23:49 | [diff] [blame] | 667 | } |
Eric Holk | ad292a8 | 2012-05-30 23:31:16 | [diff] [blame] | 668 | |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 669 | /// Controls how the task-local RNG is reseeded. |
Huon Wilson | 5442a47 | 2013-10-09 06:36:31 | [diff] [blame] | 670 | struct TaskRngReseeder; |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 671 | |
| 672 | impl reseeding::Reseeder<StdRng> for TaskRngReseeder { |
| 673 | fn reseed(&mut self, rng: &mut StdRng) { |
Huon Wilson | 5442a47 | 2013-10-09 06:36:31 | [diff] [blame] | 674 | *rng = StdRng::new(); |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 675 | } |
| 676 | } |
| 677 | static TASK_RNG_RESEED_THRESHOLD: uint = 32_768; |
| 678 | /// The task-local RNG. |
| 679 | pub type TaskRng = reseeding::ReseedingRng<StdRng, TaskRngReseeder>; |
| 680 | |
| 681 | // used to make space in TLS for a random number generator |
| 682 | local_data_key!(TASK_RNG_KEY: @mut TaskRng) |
| 683 | |
| 684 | /// Retrieve the lazily-initialized task-local random number |
| 685 | /// generator, seeded by the system. Intended to be used in method |
| 686 | /// chaining style, e.g. `task_rng().gen::<int>()`. |
| 687 | /// |
| 688 | /// The RNG provided will reseed itself from the operating system |
Huon Wilson | 5442a47 | 2013-10-09 06:36:31 | [diff] [blame] | 689 | /// after generating a certain amount of randomness. |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 690 | /// |
Huon Wilson | 5442a47 | 2013-10-09 06:36:31 | [diff] [blame] | 691 | /// The internal RNG used is platform and architecture dependent, even |
| 692 | /// if the operating system random number generator is rigged to give |
| 693 | /// the same sequence always. If absolute consistency is required, |
| 694 | /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 695 | pub fn task_rng() -> @mut TaskRng { |
Daniel Micay | 6a90e80 | 2013-09-20 06:08:47 | [diff] [blame] | 696 | let r = local_data::get(TASK_RNG_KEY, |k| k.map(|k| *k)); |
Daniel Patterson | c7354e6 | 2012-10-02 03:29:34 | [diff] [blame] | 697 | match r { |
| 698 | None => { |
Huon Wilson | 5442a47 | 2013-10-09 06:36:31 | [diff] [blame] | 699 | let rng = @mut reseeding::ReseedingRng::new(StdRng::new(), |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 700 | TASK_RNG_RESEED_THRESHOLD, |
Huon Wilson | 5442a47 | 2013-10-09 06:36:31 | [diff] [blame] | 701 | TaskRngReseeder); |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 702 | local_data::set(TASK_RNG_KEY, rng); |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 703 | rng |
Daniel Patterson | c7354e6 | 2012-10-02 03:29:34 | [diff] [blame] | 704 | } |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 705 | Some(rng) => rng |
Daniel Patterson | c7354e6 | 2012-10-02 03:29:34 | [diff] [blame] | 706 | } |
| 707 | } |
| 708 | |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 709 | // Allow direct chaining with `task_rng` |
Kevin Ballard | b8b2d1e | 2013-06-18 18:54:00 | [diff] [blame] | 710 | impl<R: Rng> Rng for @mut R { |
Graydon Hoare | d904c72 | 2013-06-18 21:45:18 | [diff] [blame] | 711 | #[inline] |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 712 | fn next_u32(&mut self) -> u32 { |
| 713 | (**self).next_u32() |
| 714 | } |
| 715 | #[inline] |
| 716 | fn next_u64(&mut self) -> u64 { |
| 717 | (**self).next_u64() |
Patrick Walton | b2d1ac1 | 2013-05-03 06:09:50 | [diff] [blame] | 718 | } |
Huon Wilson | e678435 | 2013-10-09 06:39:37 | [diff] [blame] | 719 | |
| 720 | #[inline] |
| 721 | fn fill_bytes(&mut self, bytes: &mut [u8]) { |
| 722 | (**self).fill_bytes(bytes); |
| 723 | } |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 724 | } |
| 725 | |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 726 | /// Generate a random value using the task-local random number |
| 727 | /// generator. |
| 728 | /// |
| 729 | /// # Example |
| 730 | /// |
| 731 | /// ```rust |
| 732 | /// use std::rand::random; |
| 733 | /// |
| 734 | /// fn main() { |
| 735 | /// if random() { |
| 736 | /// let x = random(); |
Huon Wilson | 9886979 | 2013-10-01 17:17:57 | [diff] [blame] | 737 | /// println!("{}", 2u * x); |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 738 | /// } else { |
Volker Mische | 82f53d6 | 2013-10-10 19:54:29 | [diff] [blame] | 739 | /// println!("{}", random::<f64>()); |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 740 | /// } |
| 741 | /// } |
| 742 | /// ``` |
Huon Wilson | d4b934b | 2013-04-26 13:53:29 | [diff] [blame] | 743 | #[inline] |
Huon Wilson | aa763cd | 2013-04-21 12:09:33 | [diff] [blame] | 744 | pub fn random<T: Rand>() -> T { |
Kevin Ballard | b8b2d1e | 2013-06-18 18:54:00 | [diff] [blame] | 745 | task_rng().gen() |
Daniel Patterson | 0b9a47a | 2012-10-02 21:15:14 | [diff] [blame] | 746 | } |
| 747 | |
Brian Anderson | 6e27b27 | 2012-01-18 03:05:07 | [diff] [blame] | 748 | #[cfg(test)] |
Graydon Hoare | d977623 | 2013-07-22 18:43:12 | [diff] [blame] | 749 | mod test { |
Daniel Micay | 6919cf5 | 2013-09-08 15:01:16 | [diff] [blame] | 750 | use iter::{Iterator, range}; |
Alex Crichton | be57d74 | 2013-03-26 20:38:07 | [diff] [blame] | 751 | use option::{Option, Some}; |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 752 | use super::*; |
Patrick Walton | e26ca35 | 2012-12-28 01:53:04 | [diff] [blame] | 753 | |
Brian Anderson | 6e27b27 | 2012-01-18 03:05:07 | [diff] [blame] | 754 | #[test] |
Huon Wilson | 39a69d3 | 2013-09-22 10:51:57 | [diff] [blame] | 755 | fn test_fill_bytes_default() { |
| 756 | let mut r = weak_rng(); |
| 757 | |
| 758 | let mut v = [0u8, .. 100]; |
| 759 | r.fill_bytes(v); |
| 760 | } |
| 761 | |
| 762 | #[test] |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 763 | fn test_gen_integer_range() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 764 | let mut r = rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 765 | for _ in range(0, 1000) { |
| 766 | let a = r.gen_integer_range(-3i, 42); |
| 767 | assert!(a >= -3 && a < 42); |
| 768 | assert_eq!(r.gen_integer_range(0, 1), 0); |
| 769 | assert_eq!(r.gen_integer_range(-12, -11), -12); |
| 770 | } |
| 771 | |
| 772 | for _ in range(0, 1000) { |
| 773 | let a = r.gen_integer_range(10, 42); |
| 774 | assert!(a >= 10 && a < 42); |
| 775 | assert_eq!(r.gen_integer_range(0, 1), 0); |
| 776 | assert_eq!(r.gen_integer_range(3_000_000u, 3_000_001), 3_000_000); |
| 777 | } |
| 778 | |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 779 | } |
| 780 | |
| 781 | #[test] |
| 782 | #[should_fail] |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 783 | fn test_gen_integer_range_fail_int() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 784 | let mut r = rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 785 | r.gen_integer_range(5i, -2); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 786 | } |
| 787 | |
| 788 | #[test] |
| 789 | #[should_fail] |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 790 | fn test_gen_integer_range_fail_uint() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 791 | let mut r = rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 792 | r.gen_integer_range(5u, 2u); |
Brian Anderson | 6e27b27 | 2012-01-18 03:05:07 | [diff] [blame] | 793 | } |
| 794 | |
| 795 | #[test] |
Daniel Micay | c9d4ad0 | 2013-09-26 06:26:09 | [diff] [blame] | 796 | fn test_gen_f64() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 797 | let mut r = rng(); |
Daniel Micay | c9d4ad0 | 2013-09-26 06:26:09 | [diff] [blame] | 798 | let a = r.gen::<f64>(); |
| 799 | let b = r.gen::<f64>(); |
Alex Crichton | daf5f5a | 2013-10-21 20:08:31 | [diff] [blame^] | 800 | debug!("{:?}", (a, b)); |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 801 | } |
| 802 | |
| 803 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 804 | fn test_gen_weighted_bool() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 805 | let mut r = rng(); |
Corey Richardson | cc57ca0 | 2013-05-19 02:02:45 | [diff] [blame] | 806 | assert_eq!(r.gen_weighted_bool(0u), true); |
| 807 | assert_eq!(r.gen_weighted_bool(1u), true); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 808 | } |
| 809 | |
| 810 | #[test] |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 811 | fn test_gen_ascii_str() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 812 | let mut r = rng(); |
Alex Crichton | daf5f5a | 2013-10-21 20:08:31 | [diff] [blame^] | 813 | debug!("{}", r.gen_ascii_str(10u)); |
| 814 | debug!("{}", r.gen_ascii_str(10u)); |
| 815 | debug!("{}", r.gen_ascii_str(10u)); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 816 | assert_eq!(r.gen_ascii_str(0u).len(), 0u); |
| 817 | assert_eq!(r.gen_ascii_str(10u).len(), 10u); |
| 818 | assert_eq!(r.gen_ascii_str(16u).len(), 16u); |
Gareth Daniel Smith | 11e8195 | 2012-05-17 18:52:49 | [diff] [blame] | 819 | } |
| 820 | |
| 821 | #[test] |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 822 | fn test_gen_vec() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 823 | let mut r = rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 824 | assert_eq!(r.gen_vec::<u8>(0u).len(), 0u); |
| 825 | assert_eq!(r.gen_vec::<u8>(10u).len(), 10u); |
| 826 | assert_eq!(r.gen_vec::<f64>(16u).len(), 16u); |
Brian Anderson | 6e27b27 | 2012-01-18 03:05:07 | [diff] [blame] | 827 | } |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 828 | |
| 829 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 830 | fn test_choose() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 831 | let mut r = rng(); |
Corey Richardson | cc57ca0 | 2013-05-19 02:02:45 | [diff] [blame] | 832 | assert_eq!(r.choose([1, 1, 1]), 1); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 833 | } |
| 834 | |
| 835 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 836 | fn test_choose_option() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 837 | let mut r = rng(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 838 | let v: &[int] = &[]; |
| 839 | assert!(r.choose_option(v).is_none()); |
| 840 | |
| 841 | let i = 1; |
| 842 | let v = [1,1,1]; |
| 843 | assert_eq!(r.choose_option(v), Some(&i)); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 844 | } |
| 845 | |
| 846 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 847 | fn test_choose_weighted() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 848 | let mut r = rng(); |
Erick Tryzelaar | dc970c1 | 2013-05-23 16:39:17 | [diff] [blame] | 849 | assert!(r.choose_weighted([ |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 850 | Weighted { weight: 1u, item: 42 }, |
Patrick Walton | d7e74b5 | 2013-03-06 21:58:02 | [diff] [blame] | 851 | ]) == 42); |
Erick Tryzelaar | dc970c1 | 2013-05-23 16:39:17 | [diff] [blame] | 852 | assert!(r.choose_weighted([ |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 853 | Weighted { weight: 0u, item: 42 }, |
| 854 | Weighted { weight: 1u, item: 43 }, |
Patrick Walton | d7e74b5 | 2013-03-06 21:58:02 | [diff] [blame] | 855 | ]) == 43); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 856 | } |
| 857 | |
| 858 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 859 | fn test_choose_weighted_option() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 860 | let mut r = rng(); |
Erick Tryzelaar | dc970c1 | 2013-05-23 16:39:17 | [diff] [blame] | 861 | assert!(r.choose_weighted_option([ |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 862 | Weighted { weight: 1u, item: 42 }, |
Patrick Walton | d7e74b5 | 2013-03-06 21:58:02 | [diff] [blame] | 863 | ]) == Some(42)); |
Erick Tryzelaar | dc970c1 | 2013-05-23 16:39:17 | [diff] [blame] | 864 | assert!(r.choose_weighted_option([ |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 865 | Weighted { weight: 0u, item: 42 }, |
| 866 | Weighted { weight: 1u, item: 43 }, |
Patrick Walton | d7e74b5 | 2013-03-06 21:58:02 | [diff] [blame] | 867 | ]) == Some(43)); |
Patrick Walton | 9653436 | 2012-08-27 23:26:35 | [diff] [blame] | 868 | let v: Option<int> = r.choose_weighted_option([]); |
Patrick Walton | 1e91595 | 2013-03-29 01:39:09 | [diff] [blame] | 869 | assert!(v.is_none()); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 870 | } |
| 871 | |
| 872 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 873 | fn test_weighted_vec() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 874 | let mut r = rng(); |
Michael Sullivan | 98e161f | 2012-06-29 23:26:56 | [diff] [blame] | 875 | let empty: ~[int] = ~[]; |
Erick Tryzelaar | dc970c1 | 2013-05-23 16:39:17 | [diff] [blame] | 876 | assert_eq!(r.weighted_vec([]), empty); |
| 877 | assert!(r.weighted_vec([ |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 878 | Weighted { weight: 0u, item: 3u }, |
| 879 | Weighted { weight: 1u, item: 2u }, |
| 880 | Weighted { weight: 2u, item: 1u }, |
Patrick Walton | d7e74b5 | 2013-03-06 21:58:02 | [diff] [blame] | 881 | ]) == ~[2u, 1u, 1u]); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 882 | } |
| 883 | |
| 884 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 885 | fn test_shuffle() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 886 | let mut r = rng(); |
Michael Sullivan | 98e161f | 2012-06-29 23:26:56 | [diff] [blame] | 887 | let empty: ~[int] = ~[]; |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 888 | assert_eq!(r.shuffle(~[]), empty); |
| 889 | assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]); |
Gareth Daniel Smith | 64130f1 | 2012-05-19 18:25:45 | [diff] [blame] | 890 | } |
Daniel Patterson | 6c7459d | 2012-10-02 03:48:33 | [diff] [blame] | 891 | |
| 892 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 893 | fn test_task_rng() { |
Patrick Walton | 16a0125 | 2013-05-08 00:57:58 | [diff] [blame] | 894 | let mut r = task_rng(); |
Huon Wilson | 4a24f10 | 2013-04-24 12:29:19 | [diff] [blame] | 895 | r.gen::<int>(); |
Huon Wilson | fb923c7 | 2013-09-20 11:47:05 | [diff] [blame] | 896 | assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]); |
| 897 | assert_eq!(r.gen_integer_range(0u, 1u), 0u); |
Daniel Patterson | 6c7459d | 2012-10-02 03:48:33 | [diff] [blame] | 898 | } |
Daniel Patterson | 0b9a47a | 2012-10-02 21:15:14 | [diff] [blame] | 899 | |
| 900 | #[test] |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 901 | fn test_random() { |
Huon Wilson | aa763cd | 2013-04-21 12:09:33 | [diff] [blame] | 902 | // not sure how to test this aside from just getting some values |
Huon Wilson | 6c0a7c7b | 2013-04-23 14:00:43 | [diff] [blame] | 903 | let _n : uint = random(); |
| 904 | let _f : f32 = random(); |
| 905 | let _o : Option<Option<i8>> = random(); |
Huon Wilson | 5667902 | 2013-04-22 09:01:48 | [diff] [blame] | 906 | let _many : ((), |
Daniel Micay | 62a3434 | 2013-09-03 23:24:12 | [diff] [blame] | 907 | (~uint, @int, ~Option<~(@u32, ~(@bool,))>), |
Huon Wilson | 5667902 | 2013-04-22 09:01:48 | [diff] [blame] | 908 | (u8, i8, u16, i16, u32, i32, u64, i64), |
Daniel Micay | c9d4ad0 | 2013-09-26 06:26:09 | [diff] [blame] | 909 | (f32, (f64, (f64,)))) = random(); |
Daniel Patterson | 0b9a47a | 2012-10-02 21:15:14 | [diff] [blame] | 910 | } |
Huon Wilson | 30266a7 | 2013-04-26 13:23:49 | [diff] [blame] | 911 | |
| 912 | #[test] |
Robert Knight | 11b3d76 | 2013-08-13 11:44:16 | [diff] [blame] | 913 | fn test_sample() { |
| 914 | let MIN_VAL = 1; |
| 915 | let MAX_VAL = 100; |
| 916 | |
| 917 | let mut r = rng(); |
| 918 | let vals = range(MIN_VAL, MAX_VAL).to_owned_vec(); |
| 919 | let small_sample = r.sample(vals.iter(), 5); |
| 920 | let large_sample = r.sample(vals.iter(), vals.len() + 5); |
| 921 | |
| 922 | assert_eq!(small_sample.len(), 5); |
| 923 | assert_eq!(large_sample.len(), vals.len()); |
| 924 | |
| 925 | assert!(small_sample.iter().all(|e| { |
| 926 | **e >= MIN_VAL && **e <= MAX_VAL |
| 927 | })); |
| 928 | } |
Huon Wilson | fb97063 | 2013-09-30 15:32:12 | [diff] [blame] | 929 | |
| 930 | #[test] |
Huon Wilson | 6f4ec72 | 2013-10-01 16:23:22 | [diff] [blame] | 931 | fn test_std_rng_seeded() { |
Huon Wilson | 71addde | 2013-10-08 13:21:26 | [diff] [blame] | 932 | let s = OSRng::new().gen_vec::<uint>(256); |
Huon Wilson | 6f4ec72 | 2013-10-01 16:23:22 | [diff] [blame] | 933 | let mut ra: StdRng = SeedableRng::from_seed(s.as_slice()); |
| 934 | let mut rb: StdRng = SeedableRng::from_seed(s.as_slice()); |
| 935 | assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); |
| 936 | } |
| 937 | |
| 938 | #[test] |
| 939 | fn test_std_rng_reseed() { |
Huon Wilson | 71addde | 2013-10-08 13:21:26 | [diff] [blame] | 940 | let s = OSRng::new().gen_vec::<uint>(256); |
Huon Wilson | 6f4ec72 | 2013-10-01 16:23:22 | [diff] [blame] | 941 | let mut r: StdRng = SeedableRng::from_seed(s.as_slice()); |
| 942 | let string1 = r.gen_ascii_str(100); |
| 943 | |
| 944 | r.reseed(s); |
| 945 | |
| 946 | let string2 = r.gen_ascii_str(100); |
| 947 | assert_eq!(string1, string2); |
| 948 | } |
Brian Anderson | 6e27b27 | 2012-01-18 03:05:07 | [diff] [blame] | 949 | } |
Graydon Hoare | d977623 | 2013-07-22 18:43:12 | [diff] [blame] | 950 | |
| 951 | #[cfg(test)] |
| 952 | mod bench { |
| 953 | use extra::test::BenchHarness; |
| 954 | use rand::*; |
Brian Anderson | 34d376f | 2013-10-17 01:34:01 | [diff] [blame] | 955 | use mem::size_of; |
Graydon Hoare | d977623 | 2013-07-22 18:43:12 | [diff] [blame] | 956 | |
| 957 | #[bench] |
| 958 | fn rand_xorshift(bh: &mut BenchHarness) { |
| 959 | let mut rng = XorShiftRng::new(); |
| 960 | do bh.iter { |
| 961 | rng.gen::<uint>(); |
| 962 | } |
| 963 | bh.bytes = size_of::<uint>() as u64; |
| 964 | } |
| 965 | |
| 966 | #[bench] |
| 967 | fn rand_isaac(bh: &mut BenchHarness) { |
| 968 | let mut rng = IsaacRng::new(); |
| 969 | do bh.iter { |
| 970 | rng.gen::<uint>(); |
| 971 | } |
| 972 | bh.bytes = size_of::<uint>() as u64; |
| 973 | } |
| 974 | |
| 975 | #[bench] |
Huon Wilson | a2b5096 | 2013-09-21 12:06:50 | [diff] [blame] | 976 | fn rand_isaac64(bh: &mut BenchHarness) { |
| 977 | let mut rng = Isaac64Rng::new(); |
| 978 | do bh.iter { |
| 979 | rng.gen::<uint>(); |
| 980 | } |
| 981 | bh.bytes = size_of::<uint>() as u64; |
| 982 | } |
| 983 | |
| 984 | #[bench] |
Huon Wilson | f39a215 | 2013-09-26 09:08:44 | [diff] [blame] | 985 | fn rand_std(bh: &mut BenchHarness) { |
| 986 | let mut rng = StdRng::new(); |
| 987 | do bh.iter { |
| 988 | rng.gen::<uint>(); |
| 989 | } |
| 990 | bh.bytes = size_of::<uint>() as u64; |
| 991 | } |
| 992 | |
| 993 | #[bench] |
Graydon Hoare | d977623 | 2013-07-22 18:43:12 | [diff] [blame] | 994 | fn rand_shuffle_100(bh: &mut BenchHarness) { |
| 995 | let mut rng = XorShiftRng::new(); |
| 996 | let x : &mut[uint] = [1,..100]; |
| 997 | do bh.iter { |
| 998 | rng.shuffle_mut(x); |
| 999 | } |
| 1000 | } |
Daniel Micay | 1fc4db2 | 2013-08-01 07:16:42 | [diff] [blame] | 1001 | } |