(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 }