libcore: unify gen_<type> methods on rand::RngUtil into the generic gen.

This moves all the basic random value generation into the Rand instances for
each type and then removes the `gen_int`, `gen_char` (etc) methods on RngUtil,
leaving only the generic `gen` and the more specialised methods.

Also, removes some imports that are redundant due to a `use core::prelude::*`
statement.
This commit is contained in:
Huon Wilson 2013-04-24 22:29:19 +10:00
parent 7b009210c6
commit 4a24f10ac6
15 changed files with 106 additions and 247 deletions

View File

@ -56,7 +56,7 @@ fn resize_at(capacity: uint) -> uint {
pub fn linear_map_with_capacity<K:Eq + Hash,V>(
initial_capacity: uint) -> HashMap<K, V> {
let r = rand::task_rng();
linear_map_with_capacity_and_keys((*r).gen_u64(), (*r).gen_u64(),
linear_map_with_capacity_and_keys(r.gen(), r.gen(),
initial_capacity)
}

View File

@ -8,7 +8,34 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Random number generation
/*!
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::<float>()`.
# 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))
}
~~~
*/
use int;
use prelude::*;
@ -20,98 +47,111 @@ 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<R: Rng>(rng: &R) -> Self;
}
impl Rand for int {
fn rand<R: Rng>(rng: &R) -> int {
rng.gen_int()
if int::bits == 32 {
rng.next() as int
} else {
rng.gen::<i64>() as int
}
}
}
impl Rand for i8 {
fn rand<R: Rng>(rng: &R) -> i8 {
rng.gen_i8()
rng.next() as i8
}
}
impl Rand for i16 {
fn rand<R: Rng>(rng: &R) -> i16 {
rng.gen_i16()
rng.next() as i16
}
}
impl Rand for i32 {
fn rand<R: Rng>(rng: &R) -> i32 {
rng.gen_i32()
rng.next() as i32
}
}
impl Rand for i64 {
fn rand<R: Rng>(rng: &R) -> i64 {
rng.gen_i64()
(rng.next() as i64 << 32) | rng.next() as i64
}
}
impl Rand for uint {
fn rand<R: Rng>(rng: &R) -> uint {
rng.gen_uint()
if uint::bits == 32 {
rng.next() as uint
} else {
rng.gen::<u64>() as uint
}
}
}
impl Rand for u8 {
fn rand<R: Rng>(rng: &R) -> u8 {
rng.gen_u8()
rng.next() as u8
}
}
impl Rand for u16 {
fn rand<R: Rng>(rng: &R) -> u16 {
rng.gen_u16()
rng.next() as u16
}
}
impl Rand for u32 {
fn rand<R: Rng>(rng: &R) -> u32 {
rng.gen_u32()
rng.next()
}
}
impl Rand for u64 {
fn rand<R: Rng>(rng: &R) -> u64 {
rng.gen_u64()
(rng.next() as u64 << 32) | rng.next() as u64
}
}
impl Rand for float {
fn rand<R: Rng>(rng: &R) -> float {
rng.gen_float()
rng.gen::<f64>() as float
}
}
impl Rand for f32 {
fn rand<R: Rng>(rng: &R) -> f32 {
rng.gen_f32()
rng.gen::<f64>() as f32
}
}
static scale : f64 = (u32::max_value as f64) + 1.0f64;
impl Rand for f64 {
fn rand<R: Rng>(rng: &R) -> f64 {
rng.gen_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 char {
fn rand<R: Rng>(rng: &R) -> char {
rng.gen_char()
rng.next() as char
}
}
impl Rand for bool {
fn rand<R: Rng>(rng: &R) -> bool {
rng.gen_bool()
rng.next() & 1u32 == 1u32
}
}
@ -151,7 +191,7 @@ tuple_impl!{A, B, C, D, E, F, G, H, I, J}
impl<T:Rand> Rand for Option<T> {
fn rand<R: Rng>(rng: &R) -> Option<T> {
if rng.gen_bool() {
if rng.gen() {
Some(rng.gen())
} else {
None
@ -195,93 +235,24 @@ pub struct Weighted<T> {
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<T:Rand>(&self) -> T;
/**
* Return a random int
*
* *Example*
*
* ~~~
*
* use core::rand::RngUtil;
*
* fn main() {
* rng = rand::rng();
* println(fmt!("%d",rng.gen_int()));
* }
* ~~~
* Return a int randomly chosen from the range [start, end),
* failing if start >= end
*/
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
*
@ -453,43 +424,13 @@ impl<R: Rng> 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_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
start + int::abs(self.gen::<int>() % (end - start))
}
/**
@ -498,51 +439,7 @@ impl<R: Rng> RngUtil for R {
*/
fn gen_uint_range(&self, start: uint, end: uint) -> uint {
assert!(start < end);
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
start + (self.gen::<uint>() % (end - start))
}
/**
@ -555,11 +452,6 @@ impl<R: Rng> 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 {
@ -588,7 +480,7 @@ impl<R: Rng> 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_u8()
self.gen()
}
}
@ -777,7 +669,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_int().
* `task_rng().gen::<int>()`.
*/
pub fn task_rng() -> @IsaacRng {
let r : Option<@IsaacRng>;
@ -796,6 +688,11 @@ pub fn task_rng() -> @IsaacRng {
}
}
// Allow direct chaining with `task_rng`
impl<R: Rng> Rng for @R {
fn next(&self) -> u32 { (*self).next() }
}
/**
* Returns a random value of a Rand type, using the task's random number
* generator.
@ -872,8 +769,8 @@ mod tests {
#[test]
fn test_gen_float() {
let r = rng();
let a = r.gen_float();
let b = r.gen_float();
let a = r.gen::<float>();
let b = r.gen::<float>();
debug!((a, b));
}
@ -966,9 +863,9 @@ mod tests {
#[test]
fn test_task_rng() {
let r = task_rng();
(*r).gen_int();
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]

View File

@ -73,8 +73,8 @@ pub fn normalize(p: ~Path) -> ~Path {
mod test {
use core::{os, rand};
use core::path::Path;
use core::rand::RngUtil;
use path_util::*;
use core::rand::RngUtil;
// Helper function to create a directory name that doesn't exist
pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path {

View File

@ -1425,7 +1425,7 @@ mod tests {
assert!(a.capacity() == uint::bits);
}
fn rng() -> rand::RandRes {
fn rng() -> rand::IsaacRng {
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
rand::IsaacRng::new_seeded(seed)
}

View File

@ -902,12 +902,8 @@ 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 +912,7 @@ mod test_tim_sort {
impl Ord for CVal {
fn lt(&self, other: &CVal) -> bool {
let rng = rand::rng();
if rng.gen_float() > 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,8 +962,7 @@ mod test_tim_sort {
fn crash_test() {
let rng = rand::rng();
let mut arr = do vec::from_fn(1000) |_i| {
let randVal = rng.gen_float();
CVal { val: randVal }
CVal { val: rng.gen() }
};
tim_sort(arr);
@ -987,8 +982,7 @@ mod test_tim_sort {
fn test_bad_Ord_impl() {
let rng = rand::rng();
let mut arr = do vec::from_fn(500) |_i| {
let randVal = rng.gen_uint();
DVal { val: randVal }
DVal { val: rng.gen() }
};
tim_sort(arr);
@ -998,14 +992,8 @@ 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() {
@ -1049,10 +1037,9 @@ mod big_tests {
for uint::range(lo, hi) |i| {
let n = 1 << i;
let arr = do vec::from_fn(n) |_i| {
rng.gen_float()
let mut arr: ~[float] = do vec::from_fn(n) |_i| {
rng.gen()
};
let mut arr = arr;
tim_sort(arr); // *sort
isSorted(arr);
@ -1076,7 +1063,7 @@ mod big_tests {
let size = arr.len();
let mut idx = 1;
while idx <= 10 {
arr[size-idx] = rng.gen_float();
arr[size-idx] = rng.gen();
idx += 1;
}
}
@ -1085,7 +1072,7 @@ mod big_tests {
for (n/100).times {
let idx = rng.gen_uint_range(0, n);
arr[idx] = rng.gen_float();
arr[idx] = rng.gen();
}
tim_sort(arr);
isSorted(arr);
@ -1121,8 +1108,8 @@ mod big_tests {
for uint::range(lo, hi) |i| {
let n = 1 << i;
let arr = do vec::from_fn(n) |_i| {
@rng.gen_float()
let arr: ~[@float] = do vec::from_fn(n) |_i| {
@rng.gen()
};
let mut arr = arr;
@ -1148,7 +1135,7 @@ mod big_tests {
let size = arr.len();
let mut idx = 1;
while idx <= 10 {
arr[size-idx] = @rng.gen_float();
arr[size-idx] = @rng.gen();
idx += 1;
}
}
@ -1157,7 +1144,7 @@ mod big_tests {
for (n/100).times {
let idx = rng.gen_uint_range(0, n);
arr[idx] = @rng.gen_float();
arr[idx] = @rng.gen();
}
tim_sort(arr);
isSorted(arr);

View File

@ -10,10 +10,8 @@
//! 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<Path> {
let r = rand::rng();

View File

@ -19,20 +19,9 @@ 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;
@ -608,12 +597,8 @@ pub mod bench {
use time::precise_time_ns;
use test::{BenchHarness, BenchSamples};
use stats::Stats;
use core::num;
use core::prelude::*;
use core::rand::RngUtil;
use core::rand;
use core::u64;
use core::vec;
pub impl BenchHarness {

View File

@ -175,11 +175,7 @@ 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]

View File

@ -698,7 +698,6 @@ mod test_treemap {
use core::iterator::*;
use super::*;
use core::rand::RngUtil;
use core::rand;
#[test]
fn find_empty() {
@ -839,8 +838,8 @@ mod test_treemap {
for 3.times {
for 90.times {
let k = rng.gen_int();
let v = rng.gen_int();
let k = rng.gen();
let v = rng.gen();
if !ctrl.contains(&(k, v)) {
assert!(map.insert(k, v));
ctrl.push((k, v));

View File

@ -15,6 +15,7 @@ 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();

View File

@ -12,7 +12,6 @@ extern mod std;
use core::hashmap::HashSet;
use std::bitv::BitvSet;
use std::treemap::TreeSet;
use core::io::WriterUtil;
struct Results {
sequential_ints: float,
@ -32,7 +31,7 @@ fn timed(result: &mut float, op: &fn()) {
}
pub impl Results {
fn bench_int<T:Set<uint>>(&mut self, rng: &rand::Rng, num_keys: uint,
fn bench_int<T:Set<uint>, R: rand::Rng>(&mut self, rng: &R, num_keys: uint,
rand_cap: uint, f: &fn() -> T) {
{
let mut set = f();
@ -70,8 +69,8 @@ pub impl Results {
}
}
fn bench_str<T:Set<~str>>(&mut self, rng: &rand::Rng, num_keys: uint,
f: &fn() -> T) {
fn bench_str<T:Set<~str>, R: rand::Rng>(&mut self, rng: &R, num_keys: uint,
f: &fn() -> T) {
{
let mut set = f();
do timed(&mut self.sequential_strings) {
@ -166,15 +165,15 @@ fn main() {
{
let rng = rand::IsaacRng::new_seeded(seed);
let mut results = empty_results();
results.bench_int(rng, num_keys, max, || TreeSet::new::<uint>());
results.bench_str(rng, num_keys, || TreeSet::new::<~str>());
results.bench_int(&rng, num_keys, max, || TreeSet::new::<uint>());
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);
}
}

View File

@ -13,8 +13,6 @@
extern mod std;
use std::time::precise_time_s;
use core::io::{Reader, ReaderUtil};
use core::rand::RngUtil;
macro_rules! bench (
@ -77,7 +75,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_bool() {
if r.gen() {
v += rv;
}
else {
@ -94,7 +92,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_bool() {
if r.gen() {
v = vec::append(v, rv);
}
else {
@ -110,7 +108,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_bool() {
if r.gen() {
v.push_all(rv);
}
else {

View File

@ -25,7 +25,6 @@ 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;
@ -51,7 +50,7 @@ fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] {
let j = j * 2i64;
let scale = scale - 1u;
let x = r.gen_float();
let x = r.gen::<float>();
if x < A {
choose_edge(i, j, scale, r)

View File

@ -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: &Rng) -> Vec2 {
let v = r.gen_float() * float::consts::pi * 2.0;
fn random_gradient<R:Rng>(r: &R) -> Vec2 {
let v = 2.0 * float::consts::pi * r.gen();
Vec2 {
x: float::cos(v) as f32,
y: float::sin(v) as f32,

View File

@ -16,7 +16,7 @@
* http://shootout.alioth.debian.org/
*/
extern mod std;
use core::io::WriterUtil;
use core::rand::Rng;
fn LINE_LENGTH() -> uint { return 60u; }