diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 49a38a00b10..98f69425aee 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -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); } } diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs index d20b05db485..534ebfb473b 100644 --- a/src/libstd/rand/isaac.rs +++ b/src/libstd/rand/isaac.rs @@ -187,7 +187,7 @@ impl IsaacRng { impl Rng for IsaacRng { #[inline] - fn next(&mut self) -> u32 { + fn next_u32(&mut self) -> u32 { if self.cnt == 0 { // make some more numbers self.isaac(); @@ -196,3 +196,234 @@ impl Rng for IsaacRng { self.rsl[self.cnt] } } + +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, +} + +impl Isaac64Rng { + /// Create a 64-bit ISAAC random number generator with a random + /// seed. + pub fn new() -> Isaac64Rng { + Isaac64Rng::new_seeded(seed(RAND_SIZE_64 as uint * 8)) + } + + /// Create a 64-bit ISAAC random number generator with a + /// seed. This can be any length, although the maximum number of + /// bytes used is 2048 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]) -> Isaac64Rng { + let mut rng = Isaac64Rng { + cnt: 0, + rsl: [0, .. RAND_SIZE_64], + mem: [0, .. RAND_SIZE_64], + 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 a 64-bit ISAAC random number generator using the + /// default fixed seed. + pub fn new_unseeded() -> Isaac64Rng { + let mut rng = Isaac64Rng { + cnt: 0, + rsl: [0, .. RAND_SIZE_64], + mem: [0, .. RAND_SIZE_64], + 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) { + 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 { + #[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) } + } +} + +#[cfg(test)] +mod test { + use super::*; + use rand::{Rng, seed}; + use option::{Option, Some}; + + #[test] + fn test_rng_seeded() { + let seed = seed(1024); + 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)); + + let seed = seed(2048); + let mut ra = Isaac64Rng::new_seeded(seed); + let mut rb = Isaac64Rng::new_seeded(seed); + assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); + } + + #[test] + fn test_rng_seeded_custom_seed() { + // much shorter than generated seeds which are 1024 & 2048 + // bytes resp. + 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)); + + let mut ra = Isaac64Rng::new_seeded(seed); + let mut rb = Isaac64Rng::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_u32(); + error2!("{:?}", r); + assert_eq!(r, 2935188040u32); + + let mut ra = Isaac64Rng::new_seeded(seed); + // Regression test that isaac is actually using the above vector + let r = ra.next_u64(); + error2!("{:?}", r); + assert!(r == 0 && r == 1); // FIXME: find true value + } +} diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 3348f5ee7f7..237ffb0e9ad 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -58,7 +58,7 @@ use uint; use vec; use libc::size_t; -pub use self::isaac::IsaacRng; +pub use self::isaac::{IsaacRng, Isaac64Rng}; pub mod distributions; pub mod isaac; @@ -74,7 +74,7 @@ impl Rand for int { #[inline] fn rand(rng: &mut R) -> int { if int::bits == 32 { - rng.next() as int + rng.gen::() as int } else { rng.gen::() as int } @@ -84,28 +84,28 @@ impl Rand for int { impl Rand for i8 { #[inline] fn rand(rng: &mut R) -> i8 { - rng.next() as i8 + rng.next_u32() as i8 } } impl Rand for i16 { #[inline] fn rand(rng: &mut R) -> i16 { - rng.next() as i16 + rng.next_u32() as i16 } } impl Rand for i32 { #[inline] fn rand(rng: &mut R) -> i32 { - rng.next() as i32 + rng.next_u32() as i32 } } impl Rand for i64 { #[inline] fn rand(rng: &mut R) -> i64 { - (rng.next() as i64 << 32) | rng.next() as i64 + rng.next_u64() as i64 } } @@ -113,7 +113,7 @@ impl Rand for uint { #[inline] fn rand(rng: &mut R) -> uint { if uint::bits == 32 { - rng.next() as uint + rng.gen::() as uint } else { rng.gen::() as uint } @@ -123,28 +123,28 @@ impl Rand for uint { impl Rand for u8 { #[inline] fn rand(rng: &mut R) -> u8 { - rng.next() as u8 + rng.next_u32() as u8 } } impl Rand for u16 { #[inline] fn rand(rng: &mut R) -> u16 { - rng.next() as u16 + rng.next_u32() as u16 } } impl Rand for u32 { #[inline] fn rand(rng: &mut R) -> u32 { - rng.next() + rng.next_u32() } } impl Rand for u64 { #[inline] fn rand(rng: &mut R) -> u64 { - (rng.next() as u64 << 32) | rng.next() as u64 + rng.next_u64() } } @@ -159,9 +159,9 @@ static SCALE : f64 = (u32::max_value as f64) + 1.0f64; impl Rand for f64 { #[inline] fn rand(rng: &mut R) -> f64 { - let u1 = rng.next() as f64; - let u2 = rng.next() as f64; - let u3 = rng.next() as f64; + let u1 = rng.next_u32() as f64; + let u2 = rng.next_u32() as f64; + let u3 = rng.next_u32() as f64; ((u1 / SCALE + u2) / SCALE + u3) / SCALE } @@ -170,7 +170,7 @@ impl Rand for f64 { impl Rand for bool { #[inline] fn rand(rng: &mut R) -> bool { - rng.next() & 1u32 == 1u32 + rng.gen::() & 1 == 1 } } @@ -252,8 +252,23 @@ pub struct Weighted { /// A random number generator pub trait Rng { - /// Return the next random integer - fn next(&mut self) -> u32; + /// Return the next random u32. + /// + /// By default this is implemented in terms of `next_u64`. An + /// implementation of this trait must provide at least one of + /// these two methods. + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + /// Return the next random 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) + } /// Return a random value of a Rand type. @@ -594,7 +609,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; @@ -680,8 +695,12 @@ pub fn task_rng() -> @mut IsaacRng { // Allow direct chaining with `task_rng` impl 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() } } @@ -700,34 +719,6 @@ mod test { use option::{Option, Some}; use super::*; - #[test] - fn test_rng_seeded() { - let seed = seed(400); - 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_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 - } - #[test] fn test_gen_integer_range() { let mut r = rng(); @@ -921,6 +912,15 @@ mod bench { bh.bytes = size_of::() as u64; } + #[bench] + fn rand_isaac64(bh: &mut BenchHarness) { + let mut rng = Isaac64Rng::new(); + do bh.iter { + rng.gen::(); + } + bh.bytes = size_of::() as u64; + } + #[bench] fn rand_shuffle_100(bh: &mut BenchHarness) { let mut rng = XorShiftRng::new(); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 2d1b57cebf5..48b894f51e0 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -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(); } } diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 3a3466eebff..bec11ff3a7d 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -109,7 +109,7 @@ fn main() { let mut rng = std::rand::IsaacRng::new_seeded([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); } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 138d5795ae1..36ebdc54922 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -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::() % 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::().to_str(); set.insert(s); } } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 402b3be9542..53da752fdc4 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -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) { diff --git a/src/test/run-pass/morestack6.rs b/src/test/run-pass/morestack6.rs index 45473193de9..a5a67ede98c 100644 --- a/src/test/run-pass/morestack6.rs +++ b/src/test/run-pass/morestack6.rs @@ -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::() % 256u32 + 256u32; + let frame_backoff = rng.gen::() % 10u32 + 1u32; task::try(|| runtest(f, frame_backoff) ); } }