From 699e95e561bd08004c91fb1824cb215499159b46 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 25 Apr 2013 17:55:41 +0200 Subject: [PATCH] Revert "libcore: unify `gen_` methods on `rand::RngUtil` into the generic `gen`." This reverts commit 4a24f10ac6f155699f086051ba6a728d9afb5ca6 as part of Felix's attempt to resolve Issue #6061. --- src/libcore/hashmap.rs | 2 +- src/libcore/rand.rs | 253 ++++++++++++++++++++++--------- src/librustpkg/path_util.rs | 2 +- src/libstd/bitv.rs | 2 +- src/libstd/sort.rs | 35 +++-- src/libstd/tempfile.rs | 2 + src/libstd/test.rs | 17 ++- src/libstd/timer.rs | 4 + src/libstd/treemap.rs | 5 +- src/test/bench/core-map.rs | 1 - src/test/bench/core-set.rs | 13 +- src/test/bench/core-std.rs | 8 +- src/test/bench/graph500-bfs.rs | 3 +- src/test/bench/noise.rs | 4 +- src/test/bench/shootout-fasta.rs | 2 +- 15 files changed, 247 insertions(+), 106 deletions(-) diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index d2be0416371be..3233207b8bd6a 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -56,7 +56,7 @@ fn resize_at(capacity: uint) -> uint { pub fn linear_map_with_capacity( initial_capacity: uint) -> HashMap { let r = rand::task_rng(); - linear_map_with_capacity_and_keys(r.gen(), r.gen(), + linear_map_with_capacity_and_keys((*r).gen_u64(), (*r).gen_u64(), initial_capacity) } diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index cdf6a5bb63ded..09c6e502a3865 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -8,34 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -Random number generation. - -The key functions are `random()` and `RngUtil::gen()`. These are polymorphic -and so can be used to generate any type that implements `Rand`. Type inference -means that often a simple call to `rand::random()` or `rng.gen()` will -suffice, but sometimes an annotation is required, e.g. `rand::random::()`. - -# Examples -~~~ -use core::rand::RngUtil; - -fn main() { - let rng = rand::rng(); - if rng.gen() { // bool - println(fmt!("int: %d, uint: %u", rng.gen(), rng.gen())) - } -} -~~~ - -~~~ -fn main () { - let tuple_ptr = rand::random::<~(f64, char)>(); - println(fmt!("%?", tuple_ptr)) -} -~~~ -*/ - +//! Random number generation use int; use prelude::*; @@ -47,111 +20,98 @@ use util; use vec; use libc::size_t; -/// A type that can be randomly generated using an Rng +/// A type that can be randomly generated using an RNG pub trait Rand { fn rand(rng: &R) -> Self; } impl Rand for int { fn rand(rng: &R) -> int { - if int::bits == 32 { - rng.next() as int - } else { - rng.gen::() as int - } + rng.gen_int() } } impl Rand for i8 { fn rand(rng: &R) -> i8 { - rng.next() as i8 + rng.gen_i8() } } impl Rand for i16 { fn rand(rng: &R) -> i16 { - rng.next() as i16 + rng.gen_i16() } } impl Rand for i32 { fn rand(rng: &R) -> i32 { - rng.next() as i32 + rng.gen_i32() } } impl Rand for i64 { fn rand(rng: &R) -> i64 { - (rng.next() as i64 << 32) | rng.next() as i64 + rng.gen_i64() } } impl Rand for uint { fn rand(rng: &R) -> uint { - if uint::bits == 32 { - rng.next() as uint - } else { - rng.gen::() as uint - } + rng.gen_uint() } } impl Rand for u8 { fn rand(rng: &R) -> u8 { - rng.next() as u8 + rng.gen_u8() } } impl Rand for u16 { fn rand(rng: &R) -> u16 { - rng.next() as u16 + rng.gen_u16() } } impl Rand for u32 { fn rand(rng: &R) -> u32 { - rng.next() + rng.gen_u32() } } impl Rand for u64 { fn rand(rng: &R) -> u64 { - (rng.next() as u64 << 32) | rng.next() as u64 + rng.gen_u64() } } impl Rand for float { fn rand(rng: &R) -> float { - rng.gen::() as float + rng.gen_float() } } impl Rand for f32 { fn rand(rng: &R) -> f32 { - rng.gen::() as f32 + rng.gen_f32() } } -static scale : f64 = (u32::max_value as f64) + 1.0f64; impl Rand for f64 { fn rand(rng: &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 + rng.gen_f64() } } impl Rand for char { fn rand(rng: &R) -> char { - rng.next() as char + rng.gen_char() } } impl Rand for bool { fn rand(rng: &R) -> bool { - rng.next() & 1u32 == 1u32 + rng.gen_bool() } } @@ -191,7 +151,7 @@ tuple_impl!{A, B, C, D, E, F, G, H, I, J} impl Rand for Option { fn rand(rng: &R) -> Option { - if rng.gen() { + if rng.gen_bool() { Some(rng.gen()) } else { None @@ -235,24 +195,93 @@ pub struct Weighted { weight: uint, item: T, } - +// this should be in gen_f64, but it causes an ICE there. +static scale : f64 = (u32::max_value as f64) + 1.0f64; pub trait RngUtil { /// Return a random value of a Rand type fn gen(&self) -> T; /** - * Return a int randomly chosen from the range [start, end), - * failing if start >= end + * Return a random int + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::rng(); + * println(fmt!("%d",rng.gen_int())); + * } + * ~~~ */ + fn gen_int(&self) -> int; fn gen_int_range(&self, start: int, end: int) -> int; + /// Return a random i8 + fn gen_i8(&self) -> i8; + /// Return a random i16 + fn gen_i16(&self) -> i16; + /// Return a random i32 + fn gen_i32(&self) -> i32; + /// Return a random i64 + fn gen_i64(&self) -> i64; + /// Return a random uint + fn gen_uint(&self) -> uint; /** * Return a uint randomly chosen from the range [start, end), * failing if start >= end */ fn gen_uint_range(&self, start: uint, end: uint) -> uint; + /// Return a random u8 + fn gen_u8(&self) -> u8; + /// Return a random u16 + fn gen_u16(&self) -> u16; + /// Return a random u32 + fn gen_u32(&self) -> u32; + /// Return a random u64 + fn gen_u64(&self) -> u64; + /** + * Return random float in the interval [0,1] + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::rng(); + * println(fmt!("%f",rng.gen_float())); + * } + * ~~~ + */ + fn gen_float(&self) -> float; + /// Return a random f32 in the interval [0,1] + fn gen_f32(&self) -> f32; + /// Return a random f64 in the interval [0,1] + fn gen_f64(&self) -> f64; + /// Return a random char + fn gen_char(&self) -> char; /** * Return a char randomly chosen from chars, failing if chars is empty */ fn gen_char_from(&self, chars: &str) -> char; + /** + * Return a random bool + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::rng(); + * println(fmt!("%b",rng.gen_bool())); + * } + * ~~~ + */ + fn gen_bool(&self) -> bool; /** * Return a bool with a 1 in n chance of true * @@ -424,13 +453,43 @@ impl RngUtil for R { Rand::rand(self) } + /// Return a random int + fn gen_int(&self) -> int { + self.gen_i64() as int + } + /** * Return an int randomly chosen from the range [start, end), * failing if start >= end */ fn gen_int_range(&self, start: int, end: int) -> int { assert!(start < end); - start + int::abs(self.gen::() % (end - start)) + start + int::abs(self.gen_int() % (end - start)) + } + + /// Return a random i8 + fn gen_i8(&self) -> i8 { + self.next() as i8 + } + + /// Return a random i16 + fn gen_i16(&self) -> i16 { + self.next() as i16 + } + + /// Return a random i32 + fn gen_i32(&self) -> i32 { + self.next() as i32 + } + + /// Return a random i64 + fn gen_i64(&self) -> i64 { + (self.next() as i64 << 32) | self.next() as i64 + } + + /// Return a random uint + fn gen_uint(&self) -> uint { + self.gen_u64() as uint } /** @@ -439,7 +498,51 @@ impl RngUtil for R { */ fn gen_uint_range(&self, start: uint, end: uint) -> uint { assert!(start < end); - start + (self.gen::() % (end - start)) + start + (self.gen_uint() % (end - start)) + } + + /// Return a random u8 + fn gen_u8(&self) -> u8 { + self.next() as u8 + } + + /// Return a random u16 + fn gen_u16(&self) -> u16 { + self.next() as u16 + } + + /// Return a random u32 + fn gen_u32(&self) -> u32 { + self.next() + } + + /// Return a random u64 + fn gen_u64(&self) -> u64 { + (self.next() as u64 << 32) | self.next() as u64 + } + + /// Return a random float in the interval [0,1] + fn gen_float(&self) -> float { + self.gen_f64() as float + } + + /// Return a random f32 in the interval [0,1] + fn gen_f32(&self) -> f32 { + self.gen_f64() as f32 + } + + /// Return a random f64 in the interval [0,1] + fn gen_f64(&self) -> f64 { + let u1 = self.next() as f64; + let u2 = self.next() as f64; + let u3 = self.next() as f64; + + return ((u1 / scale + u2) / scale + u3) / scale; + } + + /// Return a random char + fn gen_char(&self) -> char { + self.next() as char } /** @@ -452,6 +555,11 @@ impl RngUtil for R { self.choose(cs) } + /// Return a random bool + fn gen_bool(&self) -> bool { + self.next() & 1u32 == 1u32 + } + /// Return a bool with a 1-in-n chance of true fn gen_weighted_bool(&self, n: uint) -> bool { if n == 0u { @@ -480,7 +588,7 @@ impl RngUtil for R { /// Return a random byte string of the specified length fn gen_bytes(&self, len: uint) -> ~[u8] { do vec::from_fn(len) |_i| { - self.gen() + self.gen_u8() } } @@ -669,7 +777,7 @@ fn tls_rng_state(_v: @IsaacRng) {} /** * 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::()`. + * task_rng().gen_int(). */ pub fn task_rng() -> @IsaacRng { let r : Option<@IsaacRng>; @@ -688,11 +796,6 @@ pub fn task_rng() -> @IsaacRng { } } -// Allow direct chaining with `task_rng` -impl Rng for @R { - fn next(&self) -> u32 { (*self).next() } -} - /** * Returns a random value of a Rand type, using the task's random number * generator. @@ -769,8 +872,8 @@ mod tests { #[test] fn test_gen_float() { let r = rng(); - let a = r.gen::(); - let b = r.gen::(); + let a = r.gen_float(); + let b = r.gen_float(); debug!((a, b)); } @@ -863,9 +966,9 @@ mod tests { #[test] fn test_task_rng() { let r = task_rng(); - r.gen::(); - assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); - assert!(r.gen_uint_range(0u, 1u) == 0u); + (*r).gen_int(); + assert!((*r).shuffle(~[1, 1, 1]) == ~[1, 1, 1]); + assert!((*r).gen_uint_range(0u, 1u) == 0u); } #[test] diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index cd9b44c278e46..b35b9face2a8f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -73,8 +73,8 @@ pub fn normalize(p: ~Path) -> ~Path { mod test { use core::{os, rand}; use core::path::Path; - use path_util::*; use core::rand::RngUtil; + use path_util::*; // Helper function to create a directory name that doesn't exist pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path { diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 8bfa201395069..5f4d507568a10 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -1425,7 +1425,7 @@ mod tests { assert!(a.capacity() == uint::bits); } - fn rng() -> rand::IsaacRng { + fn rng() -> rand::RandRes { let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; rand::IsaacRng::new_seeded(seed) } diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index cc002bc8305a2..673daac5aab78 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -906,8 +906,12 @@ mod tests { #[cfg(test)] mod test_tim_sort { use core::prelude::*; + use sort::tim_sort; + use core::rand::RngUtil; + use core::rand; + use core::vec; struct CVal { val: float, @@ -916,7 +920,7 @@ mod test_tim_sort { impl Ord for CVal { fn lt(&self, other: &CVal) -> bool { let rng = rand::rng(); - if rng.gen::() > 0.995 { fail!(~"It's happening!!!"); } + if rng.gen_float() > 0.995 { fail!(~"It's happening!!!"); } (*self).val < other.val } fn le(&self, other: &CVal) -> bool { (*self).val <= other.val } @@ -966,7 +970,8 @@ mod test_tim_sort { fn crash_test() { let rng = rand::rng(); let mut arr = do vec::from_fn(1000) |_i| { - CVal { val: rng.gen() } + let randVal = rng.gen_float(); + CVal { val: randVal } }; tim_sort(arr); @@ -986,7 +991,8 @@ mod test_tim_sort { fn test_bad_Ord_impl() { let rng = rand::rng(); let mut arr = do vec::from_fn(500) |_i| { - DVal { val: rng.gen() } + let randVal = rng.gen_uint(); + DVal { val: randVal } }; tim_sort(arr); @@ -996,8 +1002,14 @@ mod test_tim_sort { #[cfg(test)] mod big_tests { use core::prelude::*; + use sort::*; + use core::rand::RngUtil; + use core::rand; + use core::task; + use core::uint; + use core::vec; #[test] fn test_unique() { @@ -1041,9 +1053,10 @@ mod big_tests { for uint::range(lo, hi) |i| { let n = 1 << i; - let mut arr: ~[float] = do vec::from_fn(n) |_i| { - rng.gen() + let arr = do vec::from_fn(n) |_i| { + rng.gen_float() }; + let mut arr = arr; tim_sort(arr); // *sort isSorted(arr); @@ -1067,7 +1080,7 @@ mod big_tests { let size = arr.len(); let mut idx = 1; while idx <= 10 { - arr[size-idx] = rng.gen(); + arr[size-idx] = rng.gen_float(); idx += 1; } } @@ -1076,7 +1089,7 @@ mod big_tests { for (n/100).times { let idx = rng.gen_uint_range(0, n); - arr[idx] = rng.gen(); + arr[idx] = rng.gen_float(); } tim_sort(arr); isSorted(arr); @@ -1112,8 +1125,8 @@ mod big_tests { for uint::range(lo, hi) |i| { let n = 1 << i; - let arr: ~[@float] = do vec::from_fn(n) |_i| { - @rng.gen() + let arr = do vec::from_fn(n) |_i| { + @rng.gen_float() }; let mut arr = arr; @@ -1139,7 +1152,7 @@ mod big_tests { let size = arr.len(); let mut idx = 1; while idx <= 10 { - arr[size-idx] = @rng.gen(); + arr[size-idx] = @rng.gen_float(); idx += 1; } } @@ -1148,7 +1161,7 @@ mod big_tests { for (n/100).times { let idx = rng.gen_uint_range(0, n); - arr[idx] = @rng.gen(); + arr[idx] = @rng.gen_float(); } tim_sort(arr); isSorted(arr); diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index c9bcb3b8952be..b92e652b7af9b 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -10,8 +10,10 @@ //! Temporary files and directories +use core::os; use core::prelude::*; use core::rand::RngUtil; +use core::rand; pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option { let r = rand::rng(); diff --git a/src/libstd/test.rs b/src/libstd/test.rs index f82cc25e0f618..113d66b30204d 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -19,9 +19,20 @@ use getopts; use sort; use term; +use core::cmp::Eq; + use core::to_str::ToStr; +use core::either::Either; +use core::either; +use core::io::WriterUtil; +use core::io; use core::comm::{stream, SharedChan}; +use core::option; use core::prelude::*; +use core::result; +use core::str; +use core::task; +use core::vec; pub mod rustrt { use core::libc::size_t; @@ -597,8 +608,12 @@ pub mod bench { use time::precise_time_ns; use test::{BenchHarness, BenchSamples}; use stats::Stats; - use core::prelude::*; + + use core::num; use core::rand::RngUtil; + use core::rand; + use core::u64; + use core::vec; pub impl BenchHarness { diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index 1e48ce5aa6f2e..f0daf407073af 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -175,7 +175,11 @@ mod test { use timer::*; use uv; + + use core::iter; use core::rand::RngUtil; + use core::rand; + use core::task; use core::pipes::{stream, SharedChan}; #[test] diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 020f4daefd9d6..dbb01b6ce397b 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -698,6 +698,7 @@ mod test_treemap { use core::iterator::*; use super::*; use core::rand::RngUtil; + use core::rand; #[test] fn find_empty() { @@ -838,8 +839,8 @@ mod test_treemap { for 3.times { for 90.times { - let k = rng.gen(); - let v = rng.gen(); + let k = rng.gen_int(); + let v = rng.gen_int(); if !ctrl.contains(&(k, v)) { assert!(map.insert(k, v)); ctrl.push((k, v)); diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index e216215ace7f9..0c53ccd46e8b7 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -15,7 +15,6 @@ use std::time; use std::treemap::TreeMap; use core::hashmap::{HashMap, HashSet}; use core::trie::TrieMap; -use core::rand::Rng; fn timed(label: &str, f: &fn()) { let start = time::precise_time_s(); diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index b3e3d295c0fad..2ed3f668684d8 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -12,6 +12,7 @@ extern mod std; use core::hashmap::HashSet; use std::bitv::BitvSet; use std::treemap::TreeSet; +use core::io::WriterUtil; struct Results { sequential_ints: float, @@ -31,7 +32,7 @@ fn timed(result: &mut float, op: &fn()) { } pub impl Results { - fn bench_int, R: rand::Rng>(&mut self, rng: &R, num_keys: uint, + fn bench_int>(&mut self, rng: &rand::Rng, num_keys: uint, rand_cap: uint, f: &fn() -> T) { { let mut set = f(); @@ -69,8 +70,8 @@ pub impl Results { } } - fn bench_str, R: rand::Rng>(&mut self, rng: &R, num_keys: uint, - f: &fn() -> T) { + fn bench_str>(&mut self, rng: &rand::Rng, num_keys: uint, + f: &fn() -> T) { { let mut set = f(); do timed(&mut self.sequential_strings) { @@ -165,15 +166,15 @@ fn main() { { let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(&rng, num_keys, max, || TreeSet::new::()); - results.bench_str(&rng, num_keys, || TreeSet::new::<~str>()); + results.bench_int(rng, num_keys, max, || TreeSet::new::()); + results.bench_str(rng, num_keys, || TreeSet::new::<~str>()); write_results("std::treemap::TreeSet", &results); } { let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(&rng, num_keys, max, || BitvSet::new()); + results.bench_int(rng, num_keys, max, || BitvSet::new()); write_results("std::bitv::BitvSet", &results); } } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 1af3538a0219d..8438759b5c8d3 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -13,6 +13,8 @@ extern mod std; use std::time::precise_time_s; + +use core::io::{Reader, ReaderUtil}; use core::rand::RngUtil; macro_rules! bench ( @@ -75,7 +77,7 @@ fn vec_plus() { let mut i = 0; while i < 1500 { let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); - if r.gen() { + if r.gen_bool() { v += rv; } else { @@ -92,7 +94,7 @@ fn vec_append() { let mut i = 0; while i < 1500 { let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); - if r.gen() { + if r.gen_bool() { v = vec::append(v, rv); } else { @@ -108,7 +110,7 @@ fn vec_push_all() { let mut v = ~[]; for uint::range(0, 1500) |i| { let mut rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); - if r.gen() { + if r.gen_bool() { v.push_all(rv); } else { diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index bd3de4a1b8aba..e84d8abf9790c 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -25,6 +25,7 @@ use std::time; use std::deque::Deque; use std::par; use core::hashmap::{HashMap, HashSet}; +use core::io::WriterUtil; use core::int::abs; use core::rand::RngUtil; @@ -50,7 +51,7 @@ fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { let j = j * 2i64; let scale = scale - 1u; - let x = r.gen::(); + let x = r.gen_float(); if x < A { choose_edge(i, j, scale, r) diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 0da3a2e5d68d0..e032274482a02 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -13,8 +13,8 @@ fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } #[inline(always)] fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } -fn random_gradient(r: &R) -> Vec2 { - let v = 2.0 * float::consts::pi * r.gen(); +fn random_gradient(r: &Rng) -> Vec2 { + let v = r.gen_float() * float::consts::pi * 2.0; Vec2 { x: float::cos(v) as f32, y: float::sin(v) as f32, diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 0fcf8341ac852..83e1a958d3ca8 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -16,7 +16,7 @@ * http://shootout.alioth.debian.org/ */ extern mod std; -use core::rand::Rng; +use core::io::WriterUtil; fn LINE_LENGTH() -> uint { return 60u; }