auto merge of #9695 : huonw/rust/rand2, r=alexcrichton
A pile of changes to `std::rand`: - Add the 64-bit variant of the ISAAC Rng. This also splits the `Rng.next() -> u32` method into `Rng.next_u32() -> u32` and `Rng.next_u64() -> u64` to be able to actually take advantage of the wider numbers. They have default implementations in terms of each other. (This is ~2× faster than the 32 bit one for generating anything larger than a `u32` on 64-bit computers.) - Add `ReaderRng` which just wraps a reader as an RNG, useful for `/dev/urandom`, `/dev/random`, `/dev/hwrng`, etc. This also adds the overrideable `fill_bytes` method to `Rng`, since readers can "generate" randomness more than just 8 bytes at a time. - Add an interface to `/dev/urandom` (and the windows API) that implements `Rng` (`os::OSRng`) so that it is a first-class randomness source. This means that experimenting with things like seeding hashmaps from it will be much easier. It deletes most of the C++ supporting the old form, except for thin wrappers around the Windows API; I don't have access to a windows with Rust other than the try branch. ( **Note:** on unices, this means that `OSRng` requires the runtime, so it's not possible to use it to seed the scheduler RNG; I've replaced it with direct libc calls for reading from `/dev/urandom`.) - Add the "blessed" `StdRng` which means users who just want a random number generator don't need to worry about the implementation details (which will make changing the underlying implementation from Isaac to something else will be easier, if this every happen). This actually changes between the 32 and 64-bit variants of Isaac depending on the platform at the moment. - Add a `SeedableRng` trait for random number generators that can be explicitly seeded, - Add the `ReseedingRng` wrapper for reseeding a RNG after a certain amount of randomness is emitted. (The method for reseeding is controlled via the `Reseeder` trait from the same module) - changes to the task rng: - uses `StdRng` - it will reseed itself every 32KB, that is, after outputting 32KB of random data it will read new data from the OS (via `OSRng`) - Implements `Rand` for `char`, and makes the `f32` and `f64` instances more reasonable (and more similar to most other languages I've looked at). - Documentation, examples and tests
This commit is contained in:
commit
f647ccc79c
19 changed files with 1709 additions and 582 deletions
1
mk/rt.mk
1
mk/rt.mk
|
@ -86,7 +86,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
|
|||
rt/sync/lock_and_signal.cpp \
|
||||
rt/sync/rust_thread.cpp \
|
||||
rt/rust_builtin.cpp \
|
||||
rt/rust_rng.cpp \
|
||||
rt/rust_upcall.cpp \
|
||||
rt/rust_uv.cpp \
|
||||
rt/miniz.cpp \
|
||||
|
|
|
@ -1524,8 +1524,8 @@ mod tests {
|
|||
}
|
||||
|
||||
fn rng() -> rand::IsaacRng {
|
||||
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
|
||||
rand::IsaacRng::new_seeded(seed)
|
||||
let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -1533,7 +1533,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = 0 as uint;
|
||||
do b.iter {
|
||||
bitv |= (1 << ((r.next() as uint) % uint::bits));
|
||||
bitv |= (1 << ((r.next_u32() as uint) % uint::bits));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1542,7 +1542,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = SmallBitv::new(uint::bits);
|
||||
do b.iter {
|
||||
bitv.set((r.next() as uint) % uint::bits, true);
|
||||
bitv.set((r.next_u32() as uint) % uint::bits, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1551,7 +1551,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = BigBitv::new(~[0]);
|
||||
do b.iter {
|
||||
bitv.set((r.next() as uint) % uint::bits, true);
|
||||
bitv.set((r.next_u32() as uint) % uint::bits, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1562,7 +1562,7 @@ mod tests {
|
|||
storage.grow(BENCH_BITS / uint::bits, &0u);
|
||||
let mut bitv = BigBitv::new(storage);
|
||||
do b.iter {
|
||||
bitv.set((r.next() as uint) % BENCH_BITS, true);
|
||||
bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1571,7 +1571,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = Bitv::new(BENCH_BITS, false);
|
||||
do b.iter {
|
||||
bitv.set((r.next() as uint) % BENCH_BITS, true);
|
||||
bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1580,7 +1580,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = Bitv::new(uint::bits, false);
|
||||
do b.iter {
|
||||
bitv.set((r.next() as uint) % uint::bits, true);
|
||||
bitv.set((r.next_u32() as uint) % uint::bits, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1589,7 +1589,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = BitvSet::new();
|
||||
do b.iter {
|
||||
bitv.insert((r.next() as uint) % uint::bits);
|
||||
bitv.insert((r.next_u32() as uint) % uint::bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1598,7 +1598,7 @@ mod tests {
|
|||
let mut r = rng();
|
||||
let mut bitv = BitvSet::new();
|
||||
do b.iter {
|
||||
bitv.insert((r.next() as uint) % BENCH_BITS);
|
||||
bitv.insert((r.next_u32() as uint) % BENCH_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1013,7 +1013,7 @@ mod test_treemap {
|
|||
check_equal(ctrl, &map);
|
||||
assert!(map.find(&5).is_none());
|
||||
|
||||
let mut rng = rand::IsaacRng::new_seeded(&[42]);
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(&[42]);
|
||||
|
||||
do 3.times {
|
||||
do 90.times {
|
||||
|
|
517
src/libstd/rand/isaac.rs
Normal file
517
src/libstd/rand/isaac.rs
Normal file
|
@ -0,0 +1,517 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The ISAAC random number generator.
|
||||
|
||||
use cast;
|
||||
use rand::{Rng, SeedableRng, OSRng};
|
||||
use iter::{Iterator, range, range_step, Repeat};
|
||||
use option::{None, Some};
|
||||
|
||||
static RAND_SIZE_LEN: u32 = 8;
|
||||
static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
|
||||
|
||||
/// A random number generator that uses the [ISAAC
|
||||
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
|
||||
///
|
||||
/// The ISAAC algorithm is suitable for cryptographic purposes.
|
||||
pub struct IsaacRng {
|
||||
priv cnt: u32,
|
||||
priv rsl: [u32, .. RAND_SIZE],
|
||||
priv mem: [u32, .. RAND_SIZE],
|
||||
priv a: u32,
|
||||
priv b: u32,
|
||||
priv c: u32
|
||||
}
|
||||
static EMPTY: IsaacRng = IsaacRng {
|
||||
cnt: 0,
|
||||
rsl: [0, .. RAND_SIZE],
|
||||
mem: [0, .. RAND_SIZE],
|
||||
a: 0, b: 0, c: 0
|
||||
};
|
||||
|
||||
impl IsaacRng {
|
||||
/// Create an ISAAC random number generator with a random seed.
|
||||
pub fn new() -> IsaacRng {
|
||||
let mut rng = EMPTY;
|
||||
|
||||
{
|
||||
let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)};
|
||||
OSRng::new().fill_bytes(bytes);
|
||||
}
|
||||
|
||||
rng.init(true);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator using the default
|
||||
/// fixed seed.
|
||||
pub fn new_unseeded() -> IsaacRng {
|
||||
let mut rng = EMPTY;
|
||||
rng.init(false);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Initialises `self`. If `use_rsl` is true, then use the current value
|
||||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||
/// randomly).
|
||||
fn init(&mut self, use_rsl: bool) {
|
||||
let mut a = 0x9e3779b9;
|
||||
let mut b = a;
|
||||
let mut c = a;
|
||||
let mut d = a;
|
||||
let mut e = a;
|
||||
let mut f = a;
|
||||
let mut g = a;
|
||||
let mut h = a;
|
||||
|
||||
macro_rules! mix(
|
||||
() => {{
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=c>>2; e+=b; c+=d;
|
||||
c^=d<<8; f+=c; d+=e;
|
||||
d^=e>>16; g+=d; e+=f;
|
||||
e^=f<<10; h+=e; f+=g;
|
||||
f^=g>>4; a+=f; g+=h;
|
||||
g^=h<<8; b+=g; h+=a;
|
||||
h^=a>>9; c+=h; a+=b;
|
||||
}}
|
||||
);
|
||||
|
||||
do 4.times { mix!(); }
|
||||
|
||||
if use_rsl {
|
||||
macro_rules! memloop (
|
||||
($arr:expr) => {{
|
||||
for i in range_step(0u32, RAND_SIZE, 8) {
|
||||
a+=$arr[i ]; b+=$arr[i+1];
|
||||
c+=$arr[i+2]; d+=$arr[i+3];
|
||||
e+=$arr[i+4]; f+=$arr[i+5];
|
||||
g+=$arr[i+6]; h+=$arr[i+7];
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
);
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
} else {
|
||||
for i in range_step(0u32, RAND_SIZE, 8) {
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}
|
||||
|
||||
self.isaac();
|
||||
}
|
||||
|
||||
/// Refills the output buffer (`self.rsl`)
|
||||
#[inline]
|
||||
fn isaac(&mut self) {
|
||||
self.c += 1;
|
||||
// abbreviations
|
||||
let mut a = self.a;
|
||||
let mut b = self.b + self.c;
|
||||
|
||||
static MIDPOINT: uint = RAND_SIZE as uint / 2;
|
||||
|
||||
macro_rules! ind (($x:expr) => {
|
||||
self.mem[($x >> 2) & (RAND_SIZE - 1)]
|
||||
});
|
||||
macro_rules! rngstep(
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = $j;
|
||||
let mix = if $shift < 0 {
|
||||
a >> -$shift as uint
|
||||
} else {
|
||||
a << $shift as uint
|
||||
};
|
||||
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_LEN) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
);
|
||||
|
||||
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
|
||||
for &(mr_offset, m2_offset) in r.iter() {
|
||||
for i in range_step(0u, MIDPOINT, 4) {
|
||||
rngstep!(i + 0, 13);
|
||||
rngstep!(i + 1, -6);
|
||||
rngstep!(i + 2, 2);
|
||||
rngstep!(i + 3, -16);
|
||||
}
|
||||
}
|
||||
|
||||
self.a = a;
|
||||
self.b = b;
|
||||
self.cnt = RAND_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for IsaacRng {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
if self.cnt == 0 {
|
||||
// make some more numbers
|
||||
self.isaac();
|
||||
}
|
||||
self.cnt -= 1;
|
||||
self.rsl[self.cnt]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> SeedableRng<&'self [u32]> for IsaacRng {
|
||||
fn reseed(&mut self, seed: &'self [u32]) {
|
||||
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
|
||||
// - 1], 0, 0, ...], to fill rng.rsl.
|
||||
let seed_iter = seed.iter().map(|&x| x).chain(Repeat::new(0u32));
|
||||
|
||||
for (rsl_elem, seed_elem) in self.rsl.mut_iter().zip(seed_iter) {
|
||||
*rsl_elem = seed_elem;
|
||||
}
|
||||
self.cnt = 0;
|
||||
self.a = 0;
|
||||
self.b = 0;
|
||||
self.c = 0;
|
||||
|
||||
self.init(true);
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator with a seed. This can
|
||||
/// be any length, although the maximum number of elements used is
|
||||
/// 256 and any more will be silently ignored. A generator
|
||||
/// constructed with a given seed will generate the same sequence
|
||||
/// of values as all other generators constructed with that seed.
|
||||
fn from_seed(seed: &'self [u32]) -> IsaacRng {
|
||||
let mut rng = EMPTY;
|
||||
rng.reseed(seed);
|
||||
rng
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static RAND_SIZE_64_LEN: uint = 8;
|
||||
static RAND_SIZE_64: uint = 1 << RAND_SIZE_64_LEN;
|
||||
|
||||
/// A random number generator that uses the 64-bit variant of the
|
||||
/// [ISAAC
|
||||
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
|
||||
///
|
||||
/// The ISAAC algorithm is suitable for cryptographic purposes.
|
||||
pub struct Isaac64Rng {
|
||||
priv cnt: uint,
|
||||
priv rsl: [u64, .. RAND_SIZE_64],
|
||||
priv mem: [u64, .. RAND_SIZE_64],
|
||||
priv a: u64,
|
||||
priv b: u64,
|
||||
priv c: u64,
|
||||
}
|
||||
|
||||
static EMPTY_64: Isaac64Rng = Isaac64Rng {
|
||||
cnt: 0,
|
||||
rsl: [0, .. RAND_SIZE_64],
|
||||
mem: [0, .. RAND_SIZE_64],
|
||||
a: 0, b: 0, c: 0,
|
||||
};
|
||||
|
||||
impl Isaac64Rng {
|
||||
/// Create a 64-bit ISAAC random number generator with a random
|
||||
/// seed.
|
||||
pub fn new() -> Isaac64Rng {
|
||||
let mut rng = EMPTY_64;
|
||||
{
|
||||
let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)};
|
||||
OSRng::new().fill_bytes(bytes);
|
||||
}
|
||||
rng.init(true);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Create a 64-bit ISAAC random number generator using the
|
||||
/// default fixed seed.
|
||||
pub fn new_unseeded() -> Isaac64Rng {
|
||||
let mut rng = EMPTY_64;
|
||||
rng.init(false);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Initialises `self`. If `use_rsl` is true, then use the current value
|
||||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||
/// randomly).
|
||||
fn init(&mut self, use_rsl: bool) {
|
||||
macro_rules! init (
|
||||
($var:ident) => (
|
||||
let mut $var = 0x9e3779b97f4a7c13;
|
||||
)
|
||||
);
|
||||
init!(a); init!(b); init!(c); init!(d);
|
||||
init!(e); init!(f); init!(g); init!(h);
|
||||
|
||||
macro_rules! mix(
|
||||
() => {{
|
||||
a-=e; f^=h>>9; h+=a;
|
||||
b-=f; g^=a<<9; a+=b;
|
||||
c-=g; h^=b>>23; b+=c;
|
||||
d-=h; a^=c<<15; c+=d;
|
||||
e-=a; b^=d>>14; d+=e;
|
||||
f-=b; c^=e<<20; e+=f;
|
||||
g-=c; d^=f>>17; f+=g;
|
||||
h-=d; e^=g<<14; g+=h;
|
||||
}}
|
||||
);
|
||||
|
||||
for _ in range(0, 4) { mix!(); }
|
||||
if use_rsl {
|
||||
macro_rules! memloop (
|
||||
($arr:expr) => {{
|
||||
for i in range(0, RAND_SIZE_64 / 8).map(|i| i * 8) {
|
||||
a+=$arr[i ]; b+=$arr[i+1];
|
||||
c+=$arr[i+2]; d+=$arr[i+3];
|
||||
e+=$arr[i+4]; f+=$arr[i+5];
|
||||
g+=$arr[i+6]; h+=$arr[i+7];
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
);
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
} else {
|
||||
for i in range(0, RAND_SIZE_64 / 8).map(|i| i * 8) {
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}
|
||||
|
||||
self.isaac64();
|
||||
}
|
||||
|
||||
/// Refills the output buffer (`self.rsl`)
|
||||
fn isaac64(&mut self) {
|
||||
self.c += 1;
|
||||
// abbreviations
|
||||
let mut a = self.a;
|
||||
let mut b = self.b + self.c;
|
||||
static MIDPOINT: uint = RAND_SIZE_64 / 2;
|
||||
static MP_VEC: [(uint, uint), .. 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
|
||||
macro_rules! ind (
|
||||
($x:expr) => {
|
||||
self.mem.unsafe_get(($x as uint >> 3) & (RAND_SIZE_64 - 1))
|
||||
}
|
||||
);
|
||||
macro_rules! rngstep(
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = base + $j;
|
||||
let mix = a ^ (if $shift < 0 {
|
||||
a >> -$shift as uint
|
||||
} else {
|
||||
a << $shift as uint
|
||||
});
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
|
||||
unsafe {
|
||||
let x = self.mem.unsafe_get(base + mr_offset);
|
||||
a = mix + self.mem.unsafe_get(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem.unsafe_set(base + mr_offset, y);
|
||||
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
self.rsl.unsafe_set(base + mr_offset, b);
|
||||
}
|
||||
}}
|
||||
);
|
||||
|
||||
for &(mr_offset, m2_offset) in MP_VEC.iter() {
|
||||
for base in range(0, MIDPOINT / 4).map(|i| i * 4) {
|
||||
rngstep!(0, 21);
|
||||
rngstep!(1, -5);
|
||||
rngstep!(2, 12);
|
||||
rngstep!(3, -33);
|
||||
}
|
||||
}
|
||||
|
||||
self.a = a;
|
||||
self.b = b;
|
||||
self.cnt = RAND_SIZE_64;
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for Isaac64Rng {
|
||||
// FIXME #7771: having next_u32 like this should be unnecessary
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.next_u64() as u32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
if self.cnt == 0 {
|
||||
// make some more numbers
|
||||
self.isaac64();
|
||||
}
|
||||
self.cnt -= 1;
|
||||
unsafe { self.rsl.unsafe_get(self.cnt) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> SeedableRng<&'self [u64]> for Isaac64Rng {
|
||||
fn reseed(&mut self, seed: &'self [u64]) {
|
||||
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
|
||||
// - 1], 0, 0, ...], to fill rng.rsl.
|
||||
let seed_iter = seed.iter().map(|&x| x).chain(Repeat::new(0u64));
|
||||
|
||||
for (rsl_elem, seed_elem) in self.rsl.mut_iter().zip(seed_iter) {
|
||||
*rsl_elem = seed_elem;
|
||||
}
|
||||
self.cnt = 0;
|
||||
self.a = 0;
|
||||
self.b = 0;
|
||||
self.c = 0;
|
||||
|
||||
self.init(true);
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator with a seed. This can
|
||||
/// be any length, although the maximum number of elements used is
|
||||
/// 256 and any more will be silently ignored. A generator
|
||||
/// constructed with a given seed will generate the same sequence
|
||||
/// of values as all other generators constructed with that seed.
|
||||
fn from_seed(seed: &'self [u64]) -> Isaac64Rng {
|
||||
let mut rng = EMPTY_64;
|
||||
rng.reseed(seed);
|
||||
rng
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use rand::{Rng, SeedableRng, OSRng};
|
||||
use option::Some;
|
||||
use iter::range;
|
||||
use vec;
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_rand_seeded() {
|
||||
let s = OSRng::new().gen_vec::<u32>(256);
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(s.as_slice());
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(s.as_slice());
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_rand_seeded() {
|
||||
let s = OSRng::new().gen_vec::<u64>(256);
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(s.as_slice());
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(s.as_slice());
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_seeded() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_seeded() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_reseed() {
|
||||
let s = OSRng::new().gen_vec::<u32>(256);
|
||||
let mut r: IsaacRng = SeedableRng::from_seed(s.as_slice());
|
||||
let string1 = r.gen_ascii_str(100);
|
||||
|
||||
r.reseed(s);
|
||||
|
||||
let string2 = r.gen_ascii_str(100);
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_reseed() {
|
||||
let s = OSRng::new().gen_vec::<u64>(256);
|
||||
let mut r: Isaac64Rng = SeedableRng::from_seed(s.as_slice());
|
||||
let string1 = r.gen_ascii_str(100);
|
||||
|
||||
r.reseed(s);
|
||||
|
||||
let string2 = r.gen_ascii_str(100);
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_true_values() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = vec::from_fn(10, |_| ra.next_u32());
|
||||
assert_eq!(v,
|
||||
~[447462228, 2081944040, 3163797308, 2379916134, 2377489184,
|
||||
1132373754, 536342443, 2995223415, 1265094839, 345325140]);
|
||||
|
||||
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in range(0, 10000) { rb.next_u32(); }
|
||||
|
||||
let v = vec::from_fn(10, |_| rb.next_u32());
|
||||
assert_eq!(v,
|
||||
~[612373032, 292987903, 1819311337, 3141271980, 422447569,
|
||||
310096395, 1083172510, 867909094, 2478664230, 2073577855]);
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_true_values() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = vec::from_fn(10, |_| ra.next_u64());
|
||||
assert_eq!(v,
|
||||
~[15015576812873463115, 12461067598045625862, 14818626436142668771,
|
||||
5562406406765984441, 11813289907965514161, 13443797187798420053,
|
||||
6935026941854944442, 7750800609318664042, 14428747036317928637,
|
||||
14028894460301215947]);
|
||||
|
||||
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in range(0, 10000) { rb.next_u64(); }
|
||||
|
||||
let v = vec::from_fn(10, |_| rb.next_u64());
|
||||
assert_eq!(v,
|
||||
~[13557216323596688637, 17060829581390442094, 4927582063811333743,
|
||||
2699639759356482270, 4819341314392384881, 6047100822963614452,
|
||||
11086255989965979163, 11901890363215659856, 5370800226050011580,
|
||||
16496463556025356451]);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -19,6 +19,15 @@ 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.
|
||||
|
||||
# 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.
|
||||
|
||||
# Examples
|
||||
|
||||
```rust
|
||||
|
@ -44,21 +53,23 @@ fn main () {
|
|||
*/
|
||||
|
||||
use cast;
|
||||
use cmp;
|
||||
use container::Container;
|
||||
use int;
|
||||
use iter::{Iterator, range, range_step};
|
||||
use iter::{Iterator, range};
|
||||
use local_data;
|
||||
use prelude::*;
|
||||
use str;
|
||||
use sys;
|
||||
use u32;
|
||||
use u64;
|
||||
use uint;
|
||||
use vec;
|
||||
use libc::size_t;
|
||||
|
||||
pub use self::isaac::{IsaacRng, Isaac64Rng};
|
||||
pub use self::os::OSRng;
|
||||
|
||||
pub mod distributions;
|
||||
pub mod isaac;
|
||||
pub mod os;
|
||||
pub mod reader;
|
||||
pub mod reseeding;
|
||||
mod rand_impls;
|
||||
|
||||
/// A type that can be randomly generated using an Rng
|
||||
pub trait Rand {
|
||||
|
@ -67,178 +78,6 @@ pub trait Rand {
|
|||
fn rand<R: Rng>(rng: &mut R) -> Self;
|
||||
}
|
||||
|
||||
impl Rand for int {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> int {
|
||||
if int::bits == 32 {
|
||||
rng.next() as int
|
||||
} else {
|
||||
rng.gen::<i64>() as int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i8 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i8 {
|
||||
rng.next() as i8
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i16 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i16 {
|
||||
rng.next() as i16
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i32 {
|
||||
rng.next() as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i64 {
|
||||
(rng.next() as i64 << 32) | rng.next() as i64
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for uint {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> uint {
|
||||
if uint::bits == 32 {
|
||||
rng.next() as uint
|
||||
} else {
|
||||
rng.gen::<u64>() as uint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u8 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u8 {
|
||||
rng.next() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u16 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u16 {
|
||||
rng.next() as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u32 {
|
||||
rng.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u64 {
|
||||
(rng.next() as u64 << 32) | rng.next() as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for f32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> f32 {
|
||||
rng.gen::<f64>() as f32
|
||||
}
|
||||
}
|
||||
|
||||
static SCALE : f64 = (u32::max_value as f64) + 1.0f64;
|
||||
impl Rand for f64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> f64 {
|
||||
let u1 = rng.next() as f64;
|
||||
let u2 = rng.next() as f64;
|
||||
let u3 = rng.next() as f64;
|
||||
|
||||
((u1 / SCALE + u2) / SCALE + u3) / SCALE
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for bool {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> bool {
|
||||
rng.next() & 1u32 == 1u32
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuple_impl {
|
||||
// use variables to indicate the arity of the tuple
|
||||
($($tyvar:ident),* ) => {
|
||||
// the trailing commas are for the 1 tuple
|
||||
impl<
|
||||
$( $tyvar : Rand ),*
|
||||
> Rand for ( $( $tyvar ),* , ) {
|
||||
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
|
||||
(
|
||||
// use the $tyvar's to get the appropriate number of
|
||||
// repeats (they're not actually needed)
|
||||
$(
|
||||
_rng.gen::<$tyvar>()
|
||||
),*
|
||||
,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for () {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_: &mut R) -> () { () }
|
||||
}
|
||||
tuple_impl!{A}
|
||||
tuple_impl!{A, B}
|
||||
tuple_impl!{A, B, C}
|
||||
tuple_impl!{A, B, C, D}
|
||||
tuple_impl!{A, B, C, D, E}
|
||||
tuple_impl!{A, B, C, D, E, F}
|
||||
tuple_impl!{A, B, C, D, E, F, G}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
|
||||
|
||||
impl<T:Rand> Rand for Option<T> {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> Option<T> {
|
||||
if rng.gen() {
|
||||
Some(rng.gen())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Rand> Rand for ~T {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> ~T { ~rng.gen() }
|
||||
}
|
||||
|
||||
impl<T: Rand + 'static> Rand for @T {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
|
||||
}
|
||||
|
||||
#[abi = "cdecl"]
|
||||
pub mod rustrt {
|
||||
use libc::size_t;
|
||||
|
||||
extern {
|
||||
pub fn rand_gen_seed(buf: *mut u8, sz: size_t);
|
||||
}
|
||||
}
|
||||
|
||||
/// A value with a particular weight compared to other values
|
||||
pub struct Weighted<T> {
|
||||
/// The numerical weight of this item
|
||||
|
@ -249,9 +88,92 @@ pub struct Weighted<T> {
|
|||
|
||||
/// A random number generator
|
||||
pub trait Rng {
|
||||
/// Return the next random integer
|
||||
fn next(&mut self) -> u32;
|
||||
/// Return the next random u32. This rarely needs to be called
|
||||
/// directly, prefer `r.gen()` to `r.next_u32()`.
|
||||
///
|
||||
// FIXME #7771: Should be implemented in terms of next_u64
|
||||
fn next_u32(&mut self) -> u32;
|
||||
|
||||
/// Return the next random u64. This rarely needs to be called
|
||||
/// directly, prefer `r.gen()` to `r.next_u64()`.
|
||||
///
|
||||
/// By default this is implemented in terms of `next_u32`. An
|
||||
/// implementation of this trait must provide at least one of
|
||||
/// these two methods.
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
(self.next_u32() as u64 << 32) | (self.next_u32() as u64)
|
||||
}
|
||||
|
||||
/// Fill `dest` with random data.
|
||||
///
|
||||
/// This has a default implementation in terms of `next_u64` and
|
||||
/// `next_u32`, but should be overriden by implementations that
|
||||
/// offer a more efficient solution than just calling those
|
||||
/// methods repeatedly.
|
||||
///
|
||||
/// This method does *not* have a requirement to bear any fixed
|
||||
/// relationship to the other methods, for example, it does *not*
|
||||
/// have to result in the same output as progressively filling
|
||||
/// `dest` with `self.gen::<u8>()`, and any such behaviour should
|
||||
/// not be relied upon.
|
||||
///
|
||||
/// This method should guarantee that `dest` is entirely filled
|
||||
/// with new data, and may fail if this is impossible
|
||||
/// (e.g. reading past the end of a file that is being used as the
|
||||
/// source of randomness).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{task_rng, Rng};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut v = [0u8, .. 13579];
|
||||
/// task_rng().fill_bytes(v);
|
||||
/// println!("{:?}", v);
|
||||
/// }
|
||||
/// ```
|
||||
fn fill_bytes(&mut self, mut dest: &mut [u8]) {
|
||||
// this relies on the lengths being transferred correctly when
|
||||
// transmuting between vectors like this.
|
||||
let as_u64: &mut &mut [u64] = unsafe { cast::transmute(&mut dest) };
|
||||
for dest in as_u64.mut_iter() {
|
||||
*dest = self.next_u64();
|
||||
}
|
||||
|
||||
// the above will have filled up the vector as much as
|
||||
// possible in multiples of 8 bytes.
|
||||
let mut remaining = dest.len() % 8;
|
||||
|
||||
// space for a u32
|
||||
if remaining >= 4 {
|
||||
let as_u32: &mut &mut [u32] = unsafe { cast::transmute(&mut dest) };
|
||||
as_u32[as_u32.len() - 1] = self.next_u32();
|
||||
remaining -= 4;
|
||||
}
|
||||
// exactly filled
|
||||
if remaining == 0 { return }
|
||||
|
||||
// now we know we've either got 1, 2 or 3 spots to go,
|
||||
// i.e. exactly one u32 is enough.
|
||||
let rand = self.next_u32();
|
||||
let remaining_index = dest.len() - remaining;
|
||||
match dest.mut_slice_from(remaining_index) {
|
||||
[ref mut a] => {
|
||||
*a = rand as u8;
|
||||
}
|
||||
[ref mut a, ref mut b] => {
|
||||
*a = rand as u8;
|
||||
*b = (rand >> 8) as u8;
|
||||
}
|
||||
[ref mut a, ref mut b, ref mut c] => {
|
||||
*a = rand as u8;
|
||||
*b = (rand >> 8) as u8;
|
||||
*c = (rand >> 16) as u8;
|
||||
}
|
||||
_ => fail2!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a random value of a Rand type.
|
||||
///
|
||||
|
@ -556,14 +478,105 @@ pub trait Rng {
|
|||
}
|
||||
}
|
||||
|
||||
/// A random number generator that can be explicitly seeded to produce
|
||||
/// the same stream of randomness multiple times.
|
||||
pub trait SeedableRng<Seed>: Rng {
|
||||
/// Reseed an RNG with the given seed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng: rand::StdRng = rand::SeedableRng::from_seed(&[1, 2, 3, 4]);
|
||||
/// println!("{}", rng.gen::<f64>());
|
||||
/// rng.reseed([5, 6, 7, 8]);
|
||||
/// println!("{}", rng.gen::<f64>());
|
||||
/// }
|
||||
/// ```
|
||||
fn reseed(&mut self, Seed);
|
||||
|
||||
/// Create a new RNG with the given seed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng: rand::StdRng = rand::SeedableRng::from_seed(&[1, 2, 3, 4]);
|
||||
/// println!("{}", rng.gen::<f64>());
|
||||
/// }
|
||||
/// ```
|
||||
fn from_seed(seed: Seed) -> Self;
|
||||
}
|
||||
|
||||
/// Create a random number generator with a default algorithm and seed.
|
||||
///
|
||||
/// It returns the cryptographically-safest `Rng` algorithm currently
|
||||
/// available in Rust. If you require a specifically seeded `Rng` for
|
||||
/// consistency over time you should pick one algorithm and create the
|
||||
/// `Rng` yourself.
|
||||
pub fn rng() -> IsaacRng {
|
||||
IsaacRng::new()
|
||||
///
|
||||
/// This is a very expensive operation as it has to read randomness
|
||||
/// from the operating system and use this in an expensive seeding
|
||||
/// operation. If one does not require high performance generation of
|
||||
/// random numbers, `task_rng` and/or `random` may be more
|
||||
/// appropriate.
|
||||
pub fn rng() -> StdRng {
|
||||
StdRng::new()
|
||||
}
|
||||
|
||||
/// The standard RNG. This is designed to be efficient on the current
|
||||
/// platform.
|
||||
#[cfg(not(target_word_size="64"))]
|
||||
pub struct StdRng { priv rng: IsaacRng }
|
||||
|
||||
/// The standard RNG. This is designed to be efficient on the current
|
||||
/// platform.
|
||||
#[cfg(target_word_size="64")]
|
||||
pub struct StdRng { priv rng: Isaac64Rng }
|
||||
|
||||
impl StdRng {
|
||||
/// Create a randomly seeded instance of `StdRng`. This reads
|
||||
/// randomness from the OS to seed the PRNG.
|
||||
#[cfg(not(target_word_size="64"))]
|
||||
pub fn new() -> StdRng {
|
||||
StdRng { rng: IsaacRng::new() }
|
||||
}
|
||||
/// Create a randomly seeded instance of `StdRng`. This reads
|
||||
/// randomness from the OS to seed the PRNG.
|
||||
#[cfg(target_word_size="64")]
|
||||
pub fn new() -> StdRng {
|
||||
StdRng { rng: Isaac64Rng::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for StdRng {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.rng.next_u32()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.rng.next_u64()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> SeedableRng<&'self [uint]> for StdRng {
|
||||
fn reseed(&mut self, seed: &'self [uint]) {
|
||||
// the internal RNG can just be seeded from the above
|
||||
// randomness.
|
||||
self.rng.reseed(unsafe {cast::transmute(seed)})
|
||||
}
|
||||
|
||||
fn from_seed(seed: &'self [uint]) -> StdRng {
|
||||
StdRng { rng: SeedableRng::from_seed(unsafe {cast::transmute(seed)}) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a weak random number generator with a default algorithm and seed.
|
||||
|
@ -572,188 +585,13 @@ pub fn rng() -> IsaacRng {
|
|||
/// consideration for cryptography or security. If you require a specifically
|
||||
/// seeded `Rng` for consistency over time you should pick one algorithm and
|
||||
/// create the `Rng` yourself.
|
||||
///
|
||||
/// This will read randomness from the operating system to seed the
|
||||
/// generator.
|
||||
pub fn weak_rng() -> XorShiftRng {
|
||||
XorShiftRng::new()
|
||||
}
|
||||
|
||||
static RAND_SIZE_LEN: u32 = 8;
|
||||
static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
|
||||
|
||||
/// A random number generator that uses the [ISAAC
|
||||
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
|
||||
///
|
||||
/// The ISAAC algorithm is suitable for cryptographic purposes.
|
||||
pub struct IsaacRng {
|
||||
priv cnt: u32,
|
||||
priv rsl: [u32, .. RAND_SIZE],
|
||||
priv mem: [u32, .. RAND_SIZE],
|
||||
priv a: u32,
|
||||
priv b: u32,
|
||||
priv c: u32
|
||||
}
|
||||
|
||||
impl IsaacRng {
|
||||
/// Create an ISAAC random number generator with a random seed.
|
||||
pub fn new() -> IsaacRng {
|
||||
IsaacRng::new_seeded(seed())
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator with a seed. This can be any
|
||||
/// length, although the maximum number of bytes used is 1024 and any more
|
||||
/// will be silently ignored. A generator constructed with a given seed
|
||||
/// will generate the same sequence of values as all other generators
|
||||
/// constructed with the same seed.
|
||||
pub fn new_seeded(seed: &[u8]) -> IsaacRng {
|
||||
let mut rng = IsaacRng {
|
||||
cnt: 0,
|
||||
rsl: [0, .. RAND_SIZE],
|
||||
mem: [0, .. RAND_SIZE],
|
||||
a: 0, b: 0, c: 0
|
||||
};
|
||||
|
||||
let array_size = sys::size_of_val(&rng.rsl);
|
||||
let copy_length = cmp::min(array_size, seed.len());
|
||||
|
||||
// manually create a &mut [u8] slice of randrsl to copy into.
|
||||
let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) };
|
||||
vec::bytes::copy_memory(dest, seed, copy_length);
|
||||
rng.init(true);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator using the default
|
||||
/// fixed seed.
|
||||
pub fn new_unseeded() -> IsaacRng {
|
||||
let mut rng = IsaacRng {
|
||||
cnt: 0,
|
||||
rsl: [0, .. RAND_SIZE],
|
||||
mem: [0, .. RAND_SIZE],
|
||||
a: 0, b: 0, c: 0
|
||||
};
|
||||
rng.init(false);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Initialises `self`. If `use_rsl` is true, then use the current value
|
||||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||
/// randomly).
|
||||
fn init(&mut self, use_rsl: bool) {
|
||||
let mut a = 0x9e3779b9;
|
||||
let mut b = a;
|
||||
let mut c = a;
|
||||
let mut d = a;
|
||||
let mut e = a;
|
||||
let mut f = a;
|
||||
let mut g = a;
|
||||
let mut h = a;
|
||||
|
||||
macro_rules! mix(
|
||||
() => {{
|
||||
a^=b<<11; d+=a; b+=c;
|
||||
b^=c>>2; e+=b; c+=d;
|
||||
c^=d<<8; f+=c; d+=e;
|
||||
d^=e>>16; g+=d; e+=f;
|
||||
e^=f<<10; h+=e; f+=g;
|
||||
f^=g>>4; a+=f; g+=h;
|
||||
g^=h<<8; b+=g; h+=a;
|
||||
h^=a>>9; c+=h; a+=b;
|
||||
}}
|
||||
);
|
||||
|
||||
do 4.times { mix!(); }
|
||||
|
||||
if use_rsl {
|
||||
macro_rules! memloop (
|
||||
($arr:expr) => {{
|
||||
for i in range_step(0u32, RAND_SIZE, 8) {
|
||||
a+=$arr[i ]; b+=$arr[i+1];
|
||||
c+=$arr[i+2]; d+=$arr[i+3];
|
||||
e+=$arr[i+4]; f+=$arr[i+5];
|
||||
g+=$arr[i+6]; h+=$arr[i+7];
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
);
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
} else {
|
||||
for i in range_step(0u32, RAND_SIZE, 8) {
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}
|
||||
|
||||
self.isaac();
|
||||
}
|
||||
|
||||
/// Refills the output buffer (`self.rsl`)
|
||||
#[inline]
|
||||
fn isaac(&mut self) {
|
||||
self.c += 1;
|
||||
// abbreviations
|
||||
let mut a = self.a;
|
||||
let mut b = self.b + self.c;
|
||||
|
||||
static MIDPOINT: uint = RAND_SIZE as uint / 2;
|
||||
|
||||
macro_rules! ind (($x:expr) => {
|
||||
self.mem[($x >> 2) & (RAND_SIZE - 1)]
|
||||
});
|
||||
macro_rules! rngstep(
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = $j;
|
||||
let mix = if $shift < 0 {
|
||||
a >> -$shift as uint
|
||||
} else {
|
||||
a << $shift as uint
|
||||
};
|
||||
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_LEN) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
);
|
||||
|
||||
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
|
||||
for &(mr_offset, m2_offset) in r.iter() {
|
||||
for i in range_step(0u, MIDPOINT, 4) {
|
||||
rngstep!(i + 0, 13);
|
||||
rngstep!(i + 1, -6);
|
||||
rngstep!(i + 2, 2);
|
||||
rngstep!(i + 3, -16);
|
||||
}
|
||||
}
|
||||
|
||||
self.a = a;
|
||||
self.b = b;
|
||||
self.cnt = RAND_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for IsaacRng {
|
||||
#[inline]
|
||||
fn next(&mut self) -> u32 {
|
||||
if self.cnt == 0 {
|
||||
// make some more numbers
|
||||
self.isaac();
|
||||
}
|
||||
self.cnt -= 1;
|
||||
self.rsl[self.cnt]
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Xorshift random number
|
||||
/// generator](http://en.wikipedia.org/wiki/Xorshift).
|
||||
///
|
||||
|
@ -769,7 +607,7 @@ pub struct XorShiftRng {
|
|||
|
||||
impl Rng for XorShiftRng {
|
||||
#[inline]
|
||||
fn next(&mut self) -> u32 {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
let x = self.x;
|
||||
let t = x ^ (x << 11);
|
||||
self.x = self.y;
|
||||
|
@ -781,89 +619,123 @@ impl Rng for XorShiftRng {
|
|||
}
|
||||
}
|
||||
|
||||
impl SeedableRng<[u32, .. 4]> for XorShiftRng {
|
||||
/// Reseed an XorShiftRng. This will fail if `seed` is entirely 0.
|
||||
fn reseed(&mut self, seed: [u32, .. 4]) {
|
||||
assert!(!seed.iter().all(|&x| x == 0),
|
||||
"XorShiftRng.reseed called with an all zero seed.");
|
||||
|
||||
self.x = seed[0];
|
||||
self.y = seed[1];
|
||||
self.z = seed[2];
|
||||
self.w = seed[3];
|
||||
}
|
||||
|
||||
/// Create a new XorShiftRng. This will fail if `seed` is entirely 0.
|
||||
fn from_seed(seed: [u32, .. 4]) -> XorShiftRng {
|
||||
assert!(!seed.iter().all(|&x| x == 0),
|
||||
"XorShiftRng::from_seed called with an all zero seed.");
|
||||
|
||||
XorShiftRng {
|
||||
x: seed[0],
|
||||
y: seed[1],
|
||||
z: seed[2],
|
||||
w: seed[3]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XorShiftRng {
|
||||
/// Create an xor shift random number generator with a random seed.
|
||||
pub fn new() -> XorShiftRng {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
|
||||
// generate seeds the same way as seed(), except we have a spceific size
|
||||
let mut s = [0u8, ..16];
|
||||
loop {
|
||||
do s.as_mut_buf |p, sz| {
|
||||
unsafe {
|
||||
rustrt::rand_gen_seed(p, sz as size_t);
|
||||
}
|
||||
}
|
||||
let mut r = OSRng::new();
|
||||
r.fill_bytes(s);
|
||||
|
||||
if !s.iter().all(|x| *x == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let s: &[u32, ..4] = unsafe { cast::transmute(&s) };
|
||||
XorShiftRng::new_seeded(s[0], s[1], s[2], s[3])
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random number generator using the specified seed. A generator
|
||||
* constructed with a given seed will generate the same sequence of values
|
||||
* as all other generators constructed with the same seed.
|
||||
*/
|
||||
pub fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng {
|
||||
XorShiftRng {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
w: w,
|
||||
}
|
||||
let s: [u32, ..4] = unsafe { cast::transmute(s) };
|
||||
SeedableRng::from_seed(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new random seed.
|
||||
pub fn seed() -> ~[u8] {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
/// Controls how the task-local RNG is reseeded.
|
||||
struct TaskRngReseeder;
|
||||
|
||||
unsafe {
|
||||
let n = RAND_SIZE * 4;
|
||||
let mut s = vec::from_elem(n as uint, 0_u8);
|
||||
do s.as_mut_buf |p, sz| {
|
||||
rustrt::rand_gen_seed(p, sz as size_t)
|
||||
}
|
||||
s
|
||||
impl reseeding::Reseeder<StdRng> for TaskRngReseeder {
|
||||
fn reseed(&mut self, rng: &mut StdRng) {
|
||||
*rng = StdRng::new();
|
||||
}
|
||||
}
|
||||
static TASK_RNG_RESEED_THRESHOLD: uint = 32_768;
|
||||
/// The task-local RNG.
|
||||
pub type TaskRng = reseeding::ReseedingRng<StdRng, TaskRngReseeder>;
|
||||
|
||||
// used to make space in TLS for a random number generator
|
||||
local_data_key!(tls_rng_state: @@mut IsaacRng)
|
||||
local_data_key!(TASK_RNG_KEY: @mut TaskRng)
|
||||
|
||||
/**
|
||||
* Gives back a lazily initialized task-local random number generator,
|
||||
* seeded by the system. Intended to be used in method chaining style, ie
|
||||
* `task_rng().gen::<int>()`.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn task_rng() -> @mut IsaacRng {
|
||||
let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
|
||||
/// Retrieve the lazily-initialized task-local random number
|
||||
/// generator, seeded by the system. Intended to be used in method
|
||||
/// chaining style, e.g. `task_rng().gen::<int>()`.
|
||||
///
|
||||
/// The RNG provided will reseed itself from the operating system
|
||||
/// after generating a certain amount of randomness.
|
||||
///
|
||||
/// The internal RNG used is platform and architecture dependent, even
|
||||
/// if the operating system random number generator is rigged to give
|
||||
/// the same sequence always. If absolute consistency is required,
|
||||
/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
|
||||
pub fn task_rng() -> @mut TaskRng {
|
||||
let r = local_data::get(TASK_RNG_KEY, |k| k.map(|&k| *k));
|
||||
match r {
|
||||
None => {
|
||||
let rng = @@mut IsaacRng::new_seeded(seed());
|
||||
local_data::set(tls_rng_state, rng);
|
||||
*rng
|
||||
let rng = @mut reseeding::ReseedingRng::new(StdRng::new(),
|
||||
TASK_RNG_RESEED_THRESHOLD,
|
||||
TaskRngReseeder);
|
||||
local_data::set(TASK_RNG_KEY, rng);
|
||||
rng
|
||||
}
|
||||
Some(rng) => *rng
|
||||
Some(rng) => rng
|
||||
}
|
||||
}
|
||||
|
||||
// Allow direct chaining with `task_rng`
|
||||
impl<R: Rng> Rng for @mut R {
|
||||
#[inline]
|
||||
fn next(&mut self) -> u32 {
|
||||
(**self).next()
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
(**self).next_u32()
|
||||
}
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
(**self).next_u64()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fill_bytes(&mut self, bytes: &mut [u8]) {
|
||||
(**self).fill_bytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random value of a Rand type, using the task's random number
|
||||
* generator.
|
||||
*/
|
||||
/// Generate a random value using the task-local random number
|
||||
/// generator.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::random;
|
||||
///
|
||||
/// fn main() {
|
||||
/// if random() {
|
||||
/// let x = random();
|
||||
/// println!("{}", 2u * x);
|
||||
/// } else {
|
||||
/// println!("{}", random::<float>());
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn random<T: Rand>() -> T {
|
||||
task_rng().gen()
|
||||
|
@ -876,31 +748,11 @@ mod test {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_rng_seeded() {
|
||||
let seed = seed();
|
||||
let mut ra = IsaacRng::new_seeded(seed);
|
||||
let mut rb = IsaacRng::new_seeded(seed);
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
fn test_fill_bytes_default() {
|
||||
let mut r = weak_rng();
|
||||
|
||||
#[test]
|
||||
fn test_rng_seeded_custom_seed() {
|
||||
// much shorter than generated seeds which are 1024 bytes
|
||||
let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
|
||||
let mut ra = IsaacRng::new_seeded(seed);
|
||||
let mut rb = IsaacRng::new_seeded(seed);
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_seeded_custom_seed2() {
|
||||
let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
|
||||
let mut ra = IsaacRng::new_seeded(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let r = ra.next();
|
||||
debug2!("{:?}", r);
|
||||
assert!(r == 890007737u32 // on x86_64
|
||||
|| r == 2935188040u32); // on x86
|
||||
let mut v = [0u8, .. 100];
|
||||
r.fill_bytes(v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1070,6 +922,26 @@ mod test {
|
|||
**e >= MIN_VAL && **e <= MAX_VAL
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_std_rng_seeded() {
|
||||
let s = OSRng::new().gen_vec::<uint>(256);
|
||||
let mut ra: StdRng = SeedableRng::from_seed(s.as_slice());
|
||||
let mut rb: StdRng = SeedableRng::from_seed(s.as_slice());
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_std_rng_reseed() {
|
||||
let s = OSRng::new().gen_vec::<uint>(256);
|
||||
let mut r: StdRng = SeedableRng::from_seed(s.as_slice());
|
||||
let string1 = r.gen_ascii_str(100);
|
||||
|
||||
r.reseed(s);
|
||||
|
||||
let string2 = r.gen_ascii_str(100);
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1096,6 +968,24 @@ mod bench {
|
|||
bh.bytes = size_of::<uint>() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_isaac64(bh: &mut BenchHarness) {
|
||||
let mut rng = Isaac64Rng::new();
|
||||
do bh.iter {
|
||||
rng.gen::<uint>();
|
||||
}
|
||||
bh.bytes = size_of::<uint>() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_std(bh: &mut BenchHarness) {
|
||||
let mut rng = StdRng::new();
|
||||
do bh.iter {
|
||||
rng.gen::<uint>();
|
||||
}
|
||||
bh.bytes = size_of::<uint>() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_shuffle_100(bh: &mut BenchHarness) {
|
||||
let mut rng = XorShiftRng::new();
|
||||
|
|
178
src/libstd/rand/os.rs
Normal file
178
src/libstd/rand/os.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Interfaces to the operating system provided random number
|
||||
//! generators.
|
||||
|
||||
use rand::Rng;
|
||||
use ops::Drop;
|
||||
|
||||
#[cfg(unix)]
|
||||
use rand::reader::ReaderRng;
|
||||
#[cfg(unix)]
|
||||
use rt::io::{file, Open, Read};
|
||||
|
||||
#[cfg(windows)]
|
||||
use cast;
|
||||
#[cfg(windows)]
|
||||
use libc::{c_long, DWORD, BYTE};
|
||||
#[cfg(windows)]
|
||||
type HCRYPTPROV = c_long;
|
||||
// the extern functions imported from the runtime on Windows are
|
||||
// implemented so that they either succeed or abort(), so we can just
|
||||
// assume they work when we call them.
|
||||
|
||||
/// A random number generator that retrieves randomness straight from
|
||||
/// the operating system. On Unix-like systems this reads from
|
||||
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
|
||||
///
|
||||
/// This does not block.
|
||||
#[cfg(unix)]
|
||||
pub struct OSRng {
|
||||
priv inner: ReaderRng<file::FileStream>
|
||||
}
|
||||
/// A random number generator that retrieves randomness straight from
|
||||
/// the operating system. On Unix-like systems this reads from
|
||||
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
|
||||
///
|
||||
/// This does not block.
|
||||
#[cfg(windows)]
|
||||
pub struct OSRng {
|
||||
priv hcryptprov: HCRYPTPROV
|
||||
}
|
||||
|
||||
impl OSRng {
|
||||
/// Create a new `OSRng`.
|
||||
#[cfg(unix)]
|
||||
pub fn new() -> OSRng {
|
||||
let reader = file::open(& &"/dev/urandom", Open, Read).expect("Error opening /dev/urandom");
|
||||
let reader_rng = ReaderRng::new(reader);
|
||||
|
||||
OSRng { inner: reader_rng }
|
||||
}
|
||||
|
||||
/// Create a new `OSRng`.
|
||||
#[cfg(windows)]
|
||||
pub fn new() -> OSRng {
|
||||
externfn!(fn rust_win32_rand_acquire(phProv: *mut HCRYPTPROV))
|
||||
|
||||
let mut hcp = 0;
|
||||
unsafe {rust_win32_rand_acquire(&mut hcp)};
|
||||
|
||||
OSRng { hcryptprov: hcp }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl Rng for OSRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.inner.next_u32()
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.inner.next_u64()
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
self.inner.fill_bytes(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl Rng for OSRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
let mut v = [0u8, .. 4];
|
||||
self.fill_bytes(v);
|
||||
unsafe { cast::transmute(v) }
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
let mut v = [0u8, .. 8];
|
||||
self.fill_bytes(v);
|
||||
unsafe { cast::transmute(v) }
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
externfn!(fn rust_win32_rand_gen(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: *mut BYTE))
|
||||
|
||||
do v.as_mut_buf |ptr, len| {
|
||||
unsafe {rust_win32_rand_gen(self.hcryptprov, len as DWORD, ptr)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for OSRng {
|
||||
#[cfg(unix)]
|
||||
fn drop(&mut self) {
|
||||
// ensure that OSRng is not implicitly copyable on all
|
||||
// platforms, for consistency.
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn drop(&mut self) {
|
||||
externfn!(fn rust_win32_rand_release(hProv: HCRYPTPROV))
|
||||
|
||||
unsafe {rust_win32_rand_release(self.hcryptprov)}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use rand::Rng;
|
||||
|
||||
#[test]
|
||||
fn test_os_rng() {
|
||||
let mut r = OSRng::new();
|
||||
|
||||
r.next_u32();
|
||||
r.next_u64();
|
||||
|
||||
let mut v = [0u8, .. 1000];
|
||||
r.fill_bytes(v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_rng_tasks() {
|
||||
use task;
|
||||
use comm;
|
||||
use comm::{GenericChan, GenericPort};
|
||||
use option::{None, Some};
|
||||
use iter::{Iterator, range};
|
||||
use vec::{ImmutableVector, OwnedVector};
|
||||
|
||||
let mut chans = ~[];
|
||||
for _ in range(0, 20) {
|
||||
let (p, c) = comm::stream();
|
||||
chans.push(c);
|
||||
do task::spawn_with(p) |p| {
|
||||
// wait until all the tasks are ready to go.
|
||||
p.recv();
|
||||
|
||||
// deschedule to attempt to interleave things as much
|
||||
// as possible (XXX: is this a good test?)
|
||||
let mut r = OSRng::new();
|
||||
task::deschedule();
|
||||
let mut v = [0u8, .. 1000];
|
||||
|
||||
for _ in range(0, 100) {
|
||||
r.next_u32();
|
||||
task::deschedule();
|
||||
r.next_u64();
|
||||
task::deschedule();
|
||||
r.fill_bytes(v);
|
||||
task::deschedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// start all the tasks
|
||||
for c in chans.iter() {
|
||||
c.send(())
|
||||
}
|
||||
}
|
||||
}
|
224
src/libstd/rand/rand_impls.rs
Normal file
224
src/libstd/rand/rand_impls.rs
Normal file
|
@ -0,0 +1,224 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The implementations of `Rand` for the built-in types.
|
||||
|
||||
use char;
|
||||
use int;
|
||||
use option::{Option, Some, None};
|
||||
use rand::{Rand,Rng};
|
||||
use uint;
|
||||
|
||||
impl Rand for int {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> int {
|
||||
if int::bits == 32 {
|
||||
rng.gen::<i32>() as int
|
||||
} else {
|
||||
rng.gen::<i64>() as int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i8 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i8 {
|
||||
rng.next_u32() as i8
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i16 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i16 {
|
||||
rng.next_u32() as i16
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i32 {
|
||||
rng.next_u32() as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i64 {
|
||||
rng.next_u64() as i64
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for uint {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> uint {
|
||||
if uint::bits == 32 {
|
||||
rng.gen::<u32>() as uint
|
||||
} else {
|
||||
rng.gen::<u64>() as uint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u8 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u8 {
|
||||
rng.next_u32() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u16 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u16 {
|
||||
rng.next_u32() as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u32 {
|
||||
rng.next_u32()
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u64 {
|
||||
rng.next_u64()
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for f32 {
|
||||
/// A random `f32` in the range `[0, 1)`, using 24 bits of
|
||||
/// precision.
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> f32 {
|
||||
// using any more than 24 bits will cause (e.g.) 0xffff_ffff
|
||||
// to correspond to 1 exactly, so we need to drop 8 to
|
||||
// guarantee the open end.
|
||||
|
||||
static SCALE: f32 = (1u32 << 24) as f32;
|
||||
(rng.next_u32() >> 8) as f32 / SCALE
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for f64 {
|
||||
/// A random `f64` in the range `[0, 1)`, using 53 bits of
|
||||
/// precision.
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> f64 {
|
||||
// as for f32, but using more bits.
|
||||
|
||||
static SCALE: f64 = (1u64 << 53) as f64;
|
||||
(rng.next_u64() >> 11) as f64 / SCALE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Rand for char {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> char {
|
||||
// a char is 21 bits
|
||||
static CHAR_MASK: u32 = 0x001f_ffff;
|
||||
loop {
|
||||
// Rejection sampling. About 0.2% of numbers with at most
|
||||
// 21-bits are invalid codepoints (surrogates), so this
|
||||
// will succeed first go almost every time.
|
||||
match char::from_u32(rng.next_u32() & CHAR_MASK) {
|
||||
Some(c) => return c,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for bool {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> bool {
|
||||
rng.gen::<u8>() & 1 == 1
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuple_impl {
|
||||
// use variables to indicate the arity of the tuple
|
||||
($($tyvar:ident),* ) => {
|
||||
// the trailing commas are for the 1 tuple
|
||||
impl<
|
||||
$( $tyvar : Rand ),*
|
||||
> Rand for ( $( $tyvar ),* , ) {
|
||||
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
|
||||
(
|
||||
// use the $tyvar's to get the appropriate number of
|
||||
// repeats (they're not actually needed)
|
||||
$(
|
||||
_rng.gen::<$tyvar>()
|
||||
),*
|
||||
,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for () {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_: &mut R) -> () { () }
|
||||
}
|
||||
tuple_impl!{A}
|
||||
tuple_impl!{A, B}
|
||||
tuple_impl!{A, B, C}
|
||||
tuple_impl!{A, B, C, D}
|
||||
tuple_impl!{A, B, C, D, E}
|
||||
tuple_impl!{A, B, C, D, E, F}
|
||||
tuple_impl!{A, B, C, D, E, F, G}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
|
||||
|
||||
impl<T:Rand> Rand for Option<T> {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> Option<T> {
|
||||
if rng.gen() {
|
||||
Some(rng.gen())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Rand> Rand for ~T {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> ~T { ~rng.gen() }
|
||||
}
|
||||
|
||||
impl<T: Rand + 'static> Rand for @T {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::Rng;
|
||||
struct ConstantRng(u64);
|
||||
impl Rng for ConstantRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
(**self) as u32
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
**self
|
||||
}
|
||||
}
|
||||
fn floating_point_edge_cases() {
|
||||
// the test for exact equality is correct here.
|
||||
assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0)
|
||||
assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0)
|
||||
}
|
||||
}
|
124
src/libstd/rand/reader.rs
Normal file
124
src/libstd/rand/reader.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A wrapper around any Reader to treat it as an RNG.
|
||||
|
||||
use option::{Some, None};
|
||||
use rt::io::Reader;
|
||||
use rt::io::ReaderByteConversions;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
/// An RNG that reads random bytes straight from a `Reader`. This will
|
||||
/// work best with an infinite reader, but this is not required.
|
||||
///
|
||||
/// It will fail if it there is insufficient data to fulfill a request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand::{reader, Rng};
|
||||
/// use std::rt::io::mem;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = reader::ReaderRng::new(mem::MemReader::new(~[1,2,3,4,5,6,7,8]));
|
||||
/// println!("{:x}", rng.gen::<uint>());
|
||||
/// }
|
||||
/// ```
|
||||
pub struct ReaderRng<R> {
|
||||
priv reader: R
|
||||
}
|
||||
|
||||
impl<R: Reader> ReaderRng<R> {
|
||||
/// Create a new `ReaderRng` from a `Reader`.
|
||||
pub fn new(r: R) -> ReaderRng<R> {
|
||||
ReaderRng {
|
||||
reader: r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> Rng for ReaderRng<R> {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
// This is designed for speed: reading a LE integer on a LE
|
||||
// platform just involves blitting the bytes into the memory
|
||||
// of the u32, similarly for BE on BE; avoiding byteswapping.
|
||||
if cfg!(target_endian="little") {
|
||||
self.reader.read_le_u32_()
|
||||
} else {
|
||||
self.reader.read_be_u32_()
|
||||
}
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
// see above for explanation.
|
||||
if cfg!(target_endian="little") {
|
||||
self.reader.read_le_u64_()
|
||||
} else {
|
||||
self.reader.read_be_u64_()
|
||||
}
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
if v.len() == 0 { return }
|
||||
match self.reader.read(v) {
|
||||
Some(n) if n == v.len() => return,
|
||||
Some(n) => fail2!("ReaderRng.fill_bytes could not fill buffer: \
|
||||
read {} out of {} bytes.", n, v.len()),
|
||||
None => fail2!("ReaderRng.fill_bytes reached eof.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use rt::io::mem::MemReader;
|
||||
use cast;
|
||||
|
||||
#[test]
|
||||
fn test_reader_rng_u64() {
|
||||
// transmute from the target to avoid endianness concerns.
|
||||
let v = ~[1u64, 2u64, 3u64];
|
||||
let bytes: ~[u8] = unsafe {cast::transmute(v)};
|
||||
let mut rng = ReaderRng::new(MemReader::new(bytes));
|
||||
|
||||
assert_eq!(rng.next_u64(), 1);
|
||||
assert_eq!(rng.next_u64(), 2);
|
||||
assert_eq!(rng.next_u64(), 3);
|
||||
}
|
||||
#[test]
|
||||
fn test_reader_rng_u32() {
|
||||
// transmute from the target to avoid endianness concerns.
|
||||
let v = ~[1u32, 2u32, 3u32];
|
||||
let bytes: ~[u8] = unsafe {cast::transmute(v)};
|
||||
let mut rng = ReaderRng::new(MemReader::new(bytes));
|
||||
|
||||
assert_eq!(rng.next_u32(), 1);
|
||||
assert_eq!(rng.next_u32(), 2);
|
||||
assert_eq!(rng.next_u32(), 3);
|
||||
}
|
||||
#[test]
|
||||
fn test_reader_rng_fill_bytes() {
|
||||
let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
|
||||
let mut w = [0u8, .. 8];
|
||||
|
||||
let mut rng = ReaderRng::new(MemReader::new(v.to_owned()));
|
||||
rng.fill_bytes(w);
|
||||
|
||||
assert_eq!(v, w);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_reader_rng_insufficient_bytes() {
|
||||
let mut rng = ReaderRng::new(MemReader::new(~[]));
|
||||
let mut v = [0u8, .. 3];
|
||||
rng.fill_bytes(v);
|
||||
}
|
||||
}
|
204
src/libstd/rand/reseeding.rs
Normal file
204
src/libstd/rand/reseeding.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A wrapper around another RNG that reseeds it after it
|
||||
//! generates a certain number of random bytes.
|
||||
|
||||
use rand::{Rng, SeedableRng};
|
||||
use default::Default;
|
||||
|
||||
/// How many bytes of entropy the underling RNG is allowed to generate
|
||||
/// before it is reseeded.
|
||||
static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024;
|
||||
|
||||
/// A wrapper around any RNG which reseeds the underlying RNG after it
|
||||
/// has generated a certain number of random bytes.
|
||||
pub struct ReseedingRng<R, Rsdr> {
|
||||
priv rng: R,
|
||||
priv generation_threshold: uint,
|
||||
priv bytes_generated: uint,
|
||||
/// Controls the behaviour when reseeding the RNG.
|
||||
reseeder: Rsdr
|
||||
}
|
||||
|
||||
impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
|
||||
/// Create a new `ReseedingRng` with the given parameters.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `rng`: the random number generator to use.
|
||||
/// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
|
||||
/// * `reseeder`: the reseeding object to use.
|
||||
pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
|
||||
ReseedingRng {
|
||||
rng: rng,
|
||||
generation_threshold: generation_threshold,
|
||||
bytes_generated: 0,
|
||||
reseeder: reseeder
|
||||
}
|
||||
}
|
||||
|
||||
/// Reseed the internal RNG if the number of bytes that have been
|
||||
/// generated exceed the threshold.
|
||||
pub fn reseed_if_necessary(&mut self) {
|
||||
if self.bytes_generated >= self.generation_threshold {
|
||||
self.reseeder.reseed(&mut self.rng);
|
||||
self.bytes_generated = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.reseed_if_necessary();
|
||||
self.bytes_generated += 4;
|
||||
self.rng.next_u32()
|
||||
}
|
||||
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.reseed_if_necessary();
|
||||
self.bytes_generated += 8;
|
||||
self.rng.next_u64()
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
self.reseed_if_necessary();
|
||||
self.bytes_generated += dest.len();
|
||||
self.fill_bytes(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R>>
|
||||
SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
|
||||
fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
|
||||
self.rng.reseed(seed);
|
||||
self.reseeder = rsdr;
|
||||
self.bytes_generated = 0;
|
||||
}
|
||||
/// Create a new `ReseedingRng` from the given reseeder and
|
||||
/// seed. This uses a default value for `generation_threshold`.
|
||||
fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
|
||||
ReseedingRng {
|
||||
rng: SeedableRng::from_seed(seed),
|
||||
generation_threshold: DEFAULT_GENERATION_THRESHOLD,
|
||||
bytes_generated: 0,
|
||||
reseeder: rsdr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that can be used to reseed an RNG via `ReseedingRng`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::{Rng, SeedableRng};
|
||||
/// use std::rand::reseeding::{Reseeder, ReseedingRng};
|
||||
///
|
||||
/// struct TickTockReseeder { tick: bool }
|
||||
/// impl Reseeder<rand::StdRng> for TickTockReseeder {
|
||||
/// fn reseed(&mut self, rng: &mut rand::StdRng) {
|
||||
/// let val = if self.tick {0} else {1};
|
||||
/// rng.reseed(&[val]);
|
||||
/// self.tick = !self.tick;
|
||||
/// }
|
||||
/// }
|
||||
/// fn main() {
|
||||
/// let rsdr = TickTockReseeder { tick: true };
|
||||
/// let mut rng = ReseedingRng::new(rand::StdRng::new(), 10, rsdr);
|
||||
///
|
||||
/// // this will repeat, because it gets reseeded very regularly.
|
||||
/// println(rng.gen_ascii_str(100));
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
pub trait Reseeder<R> {
|
||||
/// Reseed the given RNG.
|
||||
fn reseed(&mut self, rng: &mut R);
|
||||
}
|
||||
|
||||
/// Reseed an RNG using a `Default` instance. This reseeds by
|
||||
/// replacing the RNG with the result of a `Default::default` call.
|
||||
pub struct ReseedWithDefault;
|
||||
|
||||
impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
|
||||
fn reseed(&mut self, rng: &mut R) {
|
||||
*rng = Default::default();
|
||||
}
|
||||
}
|
||||
impl Default for ReseedWithDefault {
|
||||
fn default() -> ReseedWithDefault { ReseedWithDefault }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use rand::{SeedableRng, Rng};
|
||||
use default::Default;
|
||||
use iter::range;
|
||||
use option::{None, Some};
|
||||
|
||||
struct Counter {
|
||||
i: u32
|
||||
}
|
||||
|
||||
impl Rng for Counter {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.i += 1;
|
||||
// very random
|
||||
self.i - 1
|
||||
}
|
||||
}
|
||||
impl Default for Counter {
|
||||
fn default() -> Counter {
|
||||
Counter { i: 0 }
|
||||
}
|
||||
}
|
||||
impl SeedableRng<u32> for Counter {
|
||||
fn reseed(&mut self, seed: u32) {
|
||||
self.i = seed;
|
||||
}
|
||||
fn from_seed(seed: u32) -> Counter {
|
||||
Counter { i: seed }
|
||||
}
|
||||
}
|
||||
type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
|
||||
|
||||
#[test]
|
||||
fn test_reseeding() {
|
||||
let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
|
||||
|
||||
let mut i = 0;
|
||||
for _ in range(0, 1000) {
|
||||
assert_eq!(rs.next_u32(), i % 100);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_seeded() {
|
||||
let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
|
||||
let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_reseed() {
|
||||
let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
|
||||
let string1 = r.gen_ascii_str(100);
|
||||
|
||||
r.reseed((ReseedWithDefault, 3));
|
||||
|
||||
let string2 = r.gen_ascii_str(100);
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
}
|
|
@ -140,7 +140,7 @@ impl Scheduler {
|
|||
cleanup_job: None,
|
||||
run_anything: run_anything,
|
||||
friend_handle: friend,
|
||||
rng: XorShiftRng::new(),
|
||||
rng: new_sched_rng(),
|
||||
idle_callback: None,
|
||||
yield_check_count: 0,
|
||||
steal_for_yield: false
|
||||
|
@ -844,6 +844,54 @@ impl ClosureConverter for UnsafeTaskReceiver {
|
|||
fn to_fn(self) -> &fn(&mut Scheduler, ~Task) { unsafe { transmute(self) } }
|
||||
}
|
||||
|
||||
// On unix, we read randomness straight from /dev/urandom, but the
|
||||
// default constructor of an XorShiftRng does this via io::file, which
|
||||
// relies on the scheduler existing, so we have to manually load
|
||||
// randomness. Windows has its own C API for this, so we don't need to
|
||||
// worry there.
|
||||
#[cfg(windows)]
|
||||
fn new_sched_rng() -> XorShiftRng {
|
||||
XorShiftRng::new()
|
||||
}
|
||||
#[cfg(unix)]
|
||||
#[fixed_stack_segment] #[inline(never)]
|
||||
fn new_sched_rng() -> XorShiftRng {
|
||||
use libc;
|
||||
use sys;
|
||||
use c_str::ToCStr;
|
||||
use vec::MutableVector;
|
||||
use iter::Iterator;
|
||||
use rand::SeedableRng;
|
||||
|
||||
let fd = do "/dev/urandom".with_c_str |name| {
|
||||
unsafe { libc::open(name, libc::O_RDONLY, 0) }
|
||||
};
|
||||
if fd == -1 {
|
||||
rtabort!("could not open /dev/urandom for reading.")
|
||||
}
|
||||
|
||||
let mut seeds = [0u32, .. 4];
|
||||
let size = sys::size_of_val(&seeds);
|
||||
loop {
|
||||
let nbytes = do seeds.as_mut_buf |buf, _| {
|
||||
unsafe {
|
||||
libc::read(fd,
|
||||
buf as *mut libc::c_void,
|
||||
size as libc::size_t)
|
||||
}
|
||||
};
|
||||
rtassert!(nbytes as uint == size);
|
||||
|
||||
if !seeds.iter().all(|x| *x == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {libc::close(fd);}
|
||||
|
||||
SeedableRng::from_seed(seeds)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
extern mod extra;
|
||||
|
|
|
@ -509,7 +509,7 @@ mod test {
|
|||
do run_in_newsched_task() {
|
||||
use rand::{rng, Rng};
|
||||
let mut r = rng();
|
||||
let _ = r.next();
|
||||
let _ = r.next_u32();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "sync/lock_and_signal.h"
|
||||
#include "memory_region.h"
|
||||
#include "boxed_region.h"
|
||||
#include "rust_rng.h"
|
||||
#include "vg/valgrind.h"
|
||||
#include "sp.h"
|
||||
|
||||
|
@ -69,11 +68,6 @@ rust_env_pairs() {
|
|||
}
|
||||
#endif
|
||||
|
||||
extern "C" CDECL void
|
||||
rand_gen_seed(uint8_t* dest, size_t size) {
|
||||
rng_gen_seed(dest, size);
|
||||
}
|
||||
|
||||
extern "C" CDECL char*
|
||||
#if defined(__WIN32__)
|
||||
rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
|
||||
|
@ -654,6 +648,62 @@ rust_unset_sigprocmask() {
|
|||
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__)
|
||||
void
|
||||
win32_require(LPCTSTR fn, BOOL ok) {
|
||||
if (!ok) {
|
||||
LPTSTR buf;
|
||||
DWORD err = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &buf, 0, NULL );
|
||||
fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf);
|
||||
LocalFree((HLOCAL)buf);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_win32_rand_acquire(HCRYPTPROV* phProv) {
|
||||
win32_require
|
||||
(_T("CryptAcquireContext"),
|
||||
CryptAcquireContext(phProv, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
|
||||
|
||||
}
|
||||
extern "C" CDECL void
|
||||
rust_win32_rand_gen(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer) {
|
||||
win32_require
|
||||
(_T("CryptGenRandom"), CryptGenRandom(hProv, dwLen, pbBuffer));
|
||||
}
|
||||
extern "C" CDECL void
|
||||
rust_win32_rand_release(HCRYPTPROV hProv) {
|
||||
win32_require
|
||||
(_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// these symbols are listed in rustrt.def.in, so they need to exist; but they
|
||||
// should never be called.
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_win32_rand_acquire() {
|
||||
abort();
|
||||
}
|
||||
extern "C" CDECL void
|
||||
rust_win32_rand_gen() {
|
||||
abort();
|
||||
}
|
||||
extern "C" CDECL void
|
||||
rust_win32_rand_release() {
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#include "rust_globals.h"
|
||||
#include "rust_rng.h"
|
||||
#include "rust_util.h"
|
||||
|
||||
|
||||
#ifdef __WIN32__
|
||||
void
|
||||
win32_require(LPCTSTR fn, BOOL ok) {
|
||||
if (!ok) {
|
||||
LPTSTR buf;
|
||||
DWORD err = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &buf, 0, NULL );
|
||||
fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf);
|
||||
LocalFree((HLOCAL)buf);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
rng_gen_seed(uint8_t* dest, size_t size) {
|
||||
#ifdef __WIN32__
|
||||
HCRYPTPROV hProv;
|
||||
win32_require
|
||||
(_T("CryptAcquireContext"),
|
||||
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
|
||||
win32_require
|
||||
(_T("CryptGenRandom"), CryptGenRandom(hProv, size, (BYTE*) dest));
|
||||
win32_require
|
||||
(_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
|
||||
#else
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "error opening /dev/urandom: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
size_t amount = 0;
|
||||
do {
|
||||
ssize_t ret = read(fd, dest+amount, size-amount);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error reading /dev/urandom: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
else if (ret == 0) {
|
||||
fprintf(stderr, "somehow hit eof reading from /dev/urandom");
|
||||
abort();
|
||||
}
|
||||
amount += (size_t)ret;
|
||||
} while (amount < size);
|
||||
int ret = close(fd);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "error closing /dev/urandom: %s", strerror(errno));
|
||||
// FIXME #3697: Why does this fail sometimes?
|
||||
// abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#ifndef RUST_RNG_H
|
||||
#define RUST_RNG_H
|
||||
|
||||
void rng_gen_seed(uint8_t* dest, size_t size);
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
||||
|
||||
#endif
|
|
@ -9,7 +9,6 @@ rust_localtime
|
|||
rust_timegm
|
||||
rust_mktime
|
||||
precise_time_ns
|
||||
rand_gen_seed
|
||||
rust_path_is_dir
|
||||
rust_path_exists
|
||||
rust_get_stdin
|
||||
|
@ -23,6 +22,9 @@ rust_log_console_off
|
|||
rust_should_log_console
|
||||
rust_unset_sigprocmask
|
||||
rust_env_pairs
|
||||
rust_win32_rand_acquire
|
||||
rust_win32_rand_gen
|
||||
rust_win32_rand_release
|
||||
upcall_rust_personality
|
||||
upcall_call_shim_on_c_stack
|
||||
upcall_call_shim_on_rust_stack
|
||||
|
|
|
@ -15,7 +15,7 @@ use extra::treemap::TreeMap;
|
|||
use std::hashmap::{HashMap, HashSet};
|
||||
use std::io;
|
||||
use std::os;
|
||||
use std::rand::Rng;
|
||||
use std::rand::{Rng, IsaacRng, SeedableRng};
|
||||
use std::trie::TrieMap;
|
||||
use std::uint;
|
||||
use std::vec;
|
||||
|
@ -106,10 +106,10 @@ fn main() {
|
|||
let mut rand = vec::with_capacity(n_keys);
|
||||
|
||||
{
|
||||
let mut rng = std::rand::IsaacRng::new_seeded([1, 1, 1, 1, 1, 1, 1]);
|
||||
let mut rng: IsaacRng = SeedableRng::from_seed(&[1, 1, 1, 1, 1, 1, 1]);
|
||||
let mut set = HashSet::new();
|
||||
while set.len() != n_keys {
|
||||
let next = rng.next() as uint;
|
||||
let next = rng.gen();
|
||||
if set.insert(next) {
|
||||
rand.push(next);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ impl Results {
|
|||
let mut set = f();
|
||||
do timed(&mut self.random_ints) {
|
||||
for _ in range(0, num_keys) {
|
||||
set.insert((rng.next() as uint) % rand_cap);
|
||||
set.insert(rng.gen::<uint>() % rand_cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ impl Results {
|
|||
let mut set = f();
|
||||
do timed(&mut self.random_strings) {
|
||||
for _ in range(0, num_keys) {
|
||||
let s = (rng.next() as uint).to_str();
|
||||
let s = rng.gen::<uint>().to_str();
|
||||
set.insert(s);
|
||||
}
|
||||
}
|
||||
|
@ -163,11 +163,11 @@ fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let max = 200000;
|
||||
|
||||
{
|
||||
let mut rng = rand::IsaacRng::new_seeded(seed);
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed);
|
||||
let mut results = empty_results();
|
||||
results.bench_int(&mut rng, num_keys, max, || {
|
||||
let s: HashSet<uint> = HashSet::new();
|
||||
|
@ -181,7 +181,7 @@ fn main() {
|
|||
}
|
||||
|
||||
{
|
||||
let mut rng = rand::IsaacRng::new_seeded(seed);
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed);
|
||||
let mut results = empty_results();
|
||||
results.bench_int(&mut rng, num_keys, max, || {
|
||||
let s: TreeSet<uint> = TreeSet::new();
|
||||
|
@ -195,7 +195,7 @@ fn main() {
|
|||
}
|
||||
|
||||
{
|
||||
let mut rng = rand::IsaacRng::new_seeded(seed);
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed);
|
||||
let mut results = empty_results();
|
||||
results.bench_int(&mut rng, num_keys, max, || BitvSet::new());
|
||||
write_results("extra::bitv::BitvSet", &results);
|
||||
|
|
|
@ -76,7 +76,7 @@ fn make_random_fasta(wr: @io::Writer,
|
|||
wr.write_line(~">" + id + " " + desc);
|
||||
let mut rng = rand::rng();
|
||||
let rng = @mut MyRandom {
|
||||
last: rng.next()
|
||||
last: rng.gen()
|
||||
};
|
||||
let mut op: ~str = ~"";
|
||||
for _ in range(0u, n as uint) {
|
||||
|
|
|
@ -69,8 +69,8 @@ pub fn main() {
|
|||
let mut rng = rand::rng();
|
||||
for f in fns.iter() {
|
||||
let f = *f;
|
||||
let sz = rng.next() % 256u32 + 256u32;
|
||||
let frame_backoff = rng.next() % 10u32 + 1u32;
|
||||
let sz = rng.gen::<u32>() % 256u32 + 256u32;
|
||||
let frame_backoff = rng.gen::<u32>() % 10u32 + 1u32;
|
||||
task::try(|| runtest(f, frame_backoff) );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue