(index<- )        ./librand/rand_impls.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! The implementations of `Rand` for the built-in types.
  12  
  13  use std::char;
  14  use std::int;
  15  use std::uint;
  16  
  17  use {Rand,Rng};
  18  
  19  impl Rand for int {
  20      #[inline]
  21      fn rand<R: Rng>(rng&mut R) -> int {
  22          if int::BITS == 32 {
  23              rng.gen::<i32>() as int
  24          } else {
  25              rng.gen::<i64>() as int
  26          }
  27      }
  28  }
  29  
  30  impl Rand for i8 {
  31      #[inline]
  32      fn rand<R: Rng>(rng&mut R) -> i8 {
  33          rng.next_u32() as i8
  34      }
  35  }
  36  
  37  impl Rand for i16 {
  38      #[inline]
  39      fn rand<R: Rng>(rng&mut R) -> i16 {
  40          rng.next_u32() as i16
  41      }
  42  }
  43  
  44  impl Rand for i32 {
  45      #[inline]
  46      fn rand<R: Rng>(rng&mut R) -> i32 {
  47          rng.next_u32() as i32
  48      }
  49  }
  50  
  51  impl Rand for i64 {
  52      #[inline]
  53      fn rand<R: Rng>(rng&mut R) -> i64 {
  54          rng.next_u64() as i64
  55      }
  56  }
  57  
  58  impl Rand for uint {
  59      #[inline]
  60      fn rand<R: Rng>(rng&mut R) -> uint {
  61          if uint::BITS == 32 {
  62              rng.gen::<u32>() as uint
  63          } else {
  64              rng.gen::<u64>() as uint
  65          }
  66      }
  67  }
  68  
  69  impl Rand for u8 {
  70      #[inline]
  71      fn rand<R: Rng>(rng&mut R) -> u8 {
  72          rng.next_u32() as u8
  73      }
  74  }
  75  
  76  impl Rand for u16 {
  77      #[inline]
  78      fn rand<R: Rng>(rng&mut R) -> u16 {
  79          rng.next_u32() as u16
  80      }
  81  }
  82  
  83  impl Rand for u32 {
  84      #[inline]
  85      fn rand<R: Rng>(rng&mut R) -> u32 {
  86          rng.next_u32()
  87      }
  88  }
  89  
  90  impl Rand for u64 {
  91      #[inline]
  92      fn rand<R: Rng>(rng&mut R) -> u64 {
  93          rng.next_u64()
  94      }
  95  }
  96  
  97  macro_rules! float_impls {
  98      ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident, $ignored_bits:expr) => {
  99          mod $mod_name {
 100              use {Rand, Rng, Open01, Closed01};
 101  
 102              static SCALE: $ty = (1u64 << $mantissa_bits) as $ty;
 103  
 104              impl Rand for $ty {
 105                  /// Generate a floating point number in the half-open
 106                  /// interval `[0,1)`.
 107                  ///
 108                  /// See `Closed01` for the closed interval `[0,1]`,
 109                  /// and `Open01` for the open interval `(0,1)`.
 110                  #[inline]
 111                  fn rand<R: Rng>(rng&mut R) -> $ty {
 112                      // using any more than `mantissa_bits` bits will
 113                      // cause (e.g.) 0xffff_ffff to correspond to 1
 114                      // exactly, so we need to drop some (8 for f32, 11
 115                      // for f64) to guarantee the open end.
 116                      (rng.$method_name() >> $ignored_bits) as $ty / SCALE
 117                  }
 118              }
 119              impl Rand for Open01<$ty> {
 120                  #[inline]
 121                  fn rand<R: Rng>(rng&mut R) -> Open01<$ty> {
 122                      // add a small amount (specifically 2 bits below
 123                      // the precision of f64/f32 at 1.0), so that small
 124                      // numbers are larger than 0, but large numbers
 125                      // aren't pushed to/above 1.
 126                      Open01(((rng.$method_name() >> $ignored_bits) as $ty + 0.25) / SCALE)
 127                  }
 128              }
 129              impl Rand for Closed01<$ty> {
 130                  #[inline]
 131                  fn rand<R: Rng>(rng&mut R) -> Closed01<$ty> {
 132                      // divide by the maximum value of the numerator to
 133                      // get a non-zero probability of getting exactly
 134                      // 1.0.
 135                      Closed01((rng.$method_name() >> $ignored_bits) as $ty / (SCALE - 1.0))
 136                  }
 137              }
 138          }
 139      }
 140  }
 141  float_impls! { f64_rand_impls, f64, 53, next_u64, 11 }
 142  float_impls! { f32_rand_impls, f32, 24, next_u32, 8 }
 143  
 144  impl Rand for char {
 145      #[inline]
 146      fn rand<R: Rng>(rng&mut R) -> char {
 147          // a char is 21 bits
 148          static CHAR_MASK: u32 = 0x001f_ffff;
 149          loop {
 150              // Rejection sampling. About 0.2% of numbers with at most
 151              // 21-bits are invalid codepoints (surrogates), so this
 152              // will succeed first go almost every time.
 153              match char::from_u32(rng.next_u32() & CHAR_MASK) {
 154                  Some(c) => return c,
 155                  None => {}
 156              }
 157          }
 158      }
 159  }
 160  
 161  impl Rand for bool {
 162      #[inline]
 163      fn rand<R: Rng>(rng&mut R) -> bool {
 164          rng.gen::<u8>() & 1 == 1
 165      }
 166  }
 167  
 168  macro_rules! tuple_impl {
 169      // use variables to indicate the arity of the tuple
 170      ($($tyvar:ident),) => {
 171          // the trailing commas are for the 1 tuple
 172          impl<
 173              $( $tyvar : Rand ),*
 174              > Rand for ( $( $tyvar ),, ) {
 175  
 176              #[inline]
 177              fn rand<R: Rng>(_rng&mut R) -> ( $( $tyvar ),, ) {
 178                  (
 179                      // use the $tyvar's to get the appropriate number of
 180                      // repeats (they're not actually needed)
 181                      $(
 182                          _rng.gen::<$tyvar>()
 183                      ),*
 184                      ,
 185                  )
 186              }
 187          }
 188      }
 189  }
 190  
 191  impl Rand for () {
 192      #[inline]
 193      fn rand<R: Rng>(_&mut R) -> () { () }
 194  }
 195  tuple_impl!{A}
 196  tuple_impl!{A, B}
 197  tuple_impl!{A, B, C}
 198  tuple_impl!{A, B, C, D}
 199  tuple_impl!{A, B, C, D, E}
 200  tuple_impl!{A, B, C, D, E, F}
 201  tuple_impl!{A, B, C, D, E, F, G}
 202  tuple_impl!{A, B, C, D, E, F, G, H}
 203  tuple_impl!{A, B, C, D, E, F, G, H, I}
 204  tuple_impl!{A, B, C, D, E, F, G, H, I, J}
 205  
 206  impl<T:Rand> Rand for Option<T> {
 207      #[inline]
 208      fn rand<R: Rng>(rng&mut R) -> Option<T> {
 209          if rng.gen() {
 210              Some(rng.gen())
 211          } else {
 212              None
 213          }
 214      }
 215  }
 216  
 217  impl<T: Rand> Rand for Box<T> {
 218      #[inline]
 219      fn rand<R: Rng>(rng&mut R) -> Box<T> { box rng.gen() }
 220  }
 221  
 222  impl<T: Rand + 'static> Rand for @T {
 223      #[inline]
 224      fn rand<R: Rng>(rng&mut R) -> @T { @rng.gen() }
 225  }
 226  
 227  #[cfg(test)]
 228  mod tests {
 229      use {Rng, task_rng, Open01, Closed01};
 230  
 231      struct ConstantRng(u64);
 232      impl Rng for ConstantRng {
 233          fn next_u32(&mut self) -> u32 {
 234              let ConstantRng(v) = *self;
 235              v as u32
 236          }
 237          fn next_u64(&mut self) -> u64 {
 238              let ConstantRng(v) = *self;
 239              v
 240          }
 241      }
 242  
 243      #[test]
 244      fn floating_point_edge_cases() {
 245          // the test for exact equality is correct here.
 246          assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0)
 247          assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0)
 248      }
 249  
 250      #[test]
 251      fn rand_open() {
 252          // this is unlikely to catch an incorrect implementation that
 253          // generates exactly 0 or 1, but it keeps it sane.
 254          let mut rng = task_rng();
 255          for _ in range(0, 1_000) {
 256              // strict inequalities
 257              let Open01(f) = rng.gen::<Open01<f64>>();
 258              assert!(0.0 < f && f < 1.0);
 259  
 260              let Open01(f) = rng.gen::<Open01<f32>>();
 261              assert!(0.0 < f && f < 1.0);
 262          }
 263      }
 264  
 265      #[test]
 266      fn rand_closed() {
 267          let mut rng = task_rng();
 268          for _ in range(0, 1_000) {
 269              // strict inequalities
 270              let Closed01(f) = rng.gen::<Closed01<f64>>();
 271              assert!(0.0 <= f && f <= 1.0);
 272  
 273              let Closed01(f) = rng.gen::<Closed01<f32>>();
 274              assert!(0.0 <= f && f <= 1.0);
 275          }
 276      }
 277  }