6fa4bbeed4
This functionality is not super-core and so doesn't need to be included in std. It's possible that std may need rand (it does a little bit now, for io::test) in which case the functionality required could be moved to a secret hidden module and reexposed by librand. Unfortunately, using #[deprecated] here is hard: there's too much to mock to make it feasible, since we have to ensure that programs still typecheck to reach the linting phase.
278 lines
7.3 KiB
Rust
278 lines
7.3 KiB
Rust
// Copyright 2013-2014 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 std::char;
|
|
use std::int;
|
|
use std::uint;
|
|
|
|
use {Rand,Rng};
|
|
|
|
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()
|
|
}
|
|
}
|
|
|
|
macro_rules! float_impls {
|
|
($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident, $ignored_bits:expr) => {
|
|
mod $mod_name {
|
|
use {Rand, Rng, Open01, Closed01};
|
|
|
|
static SCALE: $ty = (1u64 << $mantissa_bits) as $ty;
|
|
|
|
impl Rand for $ty {
|
|
/// Generate a floating point number in the half-open
|
|
/// interval `[0,1)`.
|
|
///
|
|
/// See `Closed01` for the closed interval `[0,1]`,
|
|
/// and `Open01` for the open interval `(0,1)`.
|
|
#[inline]
|
|
fn rand<R: Rng>(rng: &mut R) -> $ty {
|
|
// using any more than `mantissa_bits` bits will
|
|
// cause (e.g.) 0xffff_ffff to correspond to 1
|
|
// exactly, so we need to drop some (8 for f32, 11
|
|
// for f64) to guarantee the open end.
|
|
(rng.$method_name() >> $ignored_bits) as $ty / SCALE
|
|
}
|
|
}
|
|
impl Rand for Open01<$ty> {
|
|
#[inline]
|
|
fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
|
|
// add a small amount (specifically 2 bits below
|
|
// the precision of f64/f32 at 1.0), so that small
|
|
// numbers are larger than 0, but large numbers
|
|
// aren't pushed to/above 1.
|
|
Open01(((rng.$method_name() >> $ignored_bits) as $ty + 0.25) / SCALE)
|
|
}
|
|
}
|
|
impl Rand for Closed01<$ty> {
|
|
#[inline]
|
|
fn rand<R: Rng>(rng: &mut R) -> Closed01<$ty> {
|
|
// divide by the maximum value of the numerator to
|
|
// get a non-zero probability of getting exactly
|
|
// 1.0.
|
|
Closed01((rng.$method_name() >> $ignored_bits) as $ty / (SCALE - 1.0))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
float_impls! { f64_rand_impls, f64, 53, next_u64, 11 }
|
|
float_impls! { f32_rand_impls, f32, 24, next_u32, 8 }
|
|
|
|
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 {Rng, task_rng, Open01, Closed01};
|
|
|
|
struct ConstantRng(u64);
|
|
impl Rng for ConstantRng {
|
|
fn next_u32(&mut self) -> u32 {
|
|
let ConstantRng(v) = *self;
|
|
v as u32
|
|
}
|
|
fn next_u64(&mut self) -> u64 {
|
|
let ConstantRng(v) = *self;
|
|
v
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
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)
|
|
}
|
|
|
|
#[test]
|
|
fn rand_open() {
|
|
// this is unlikely to catch an incorrect implementation that
|
|
// generates exactly 0 or 1, but it keeps it sane.
|
|
let mut rng = task_rng();
|
|
for _ in range(0, 1_000) {
|
|
// strict inequalities
|
|
let Open01(f) = rng.gen::<Open01<f64>>();
|
|
assert!(0.0 < f && f < 1.0);
|
|
|
|
let Open01(f) = rng.gen::<Open01<f32>>();
|
|
assert!(0.0 < f && f < 1.0);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn rand_closed() {
|
|
let mut rng = task_rng();
|
|
for _ in range(0, 1_000) {
|
|
// strict inequalities
|
|
let Closed01(f) = rng.gen::<Closed01<f64>>();
|
|
assert!(0.0 <= f && f <= 1.0);
|
|
|
|
let Closed01(f) = rng.gen::<Closed01<f32>>();
|
|
assert!(0.0 <= f && f <= 1.0);
|
|
}
|
|
}
|
|
}
|