]> git.proxmox.com Git - rustc.git/blob - src/librand/rand_impls.rs
Merge tag 'upstream-tar/1.0.0_0alpha'
[rustc.git] / src / librand / rand_impls.rs
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 core::prelude::*;
14 use core::char;
15 use core::int;
16 use core::uint;
17
18 use {Rand,Rng};
19
20 impl Rand for int {
21 #[inline]
22 fn rand<R: Rng>(rng: &mut R) -> int {
23 if int::BITS == 32 {
24 rng.gen::<i32>() as int
25 } else {
26 rng.gen::<i64>() as int
27 }
28 }
29 }
30
31 impl Rand for i8 {
32 #[inline]
33 fn rand<R: Rng>(rng: &mut R) -> i8 {
34 rng.next_u32() as i8
35 }
36 }
37
38 impl Rand for i16 {
39 #[inline]
40 fn rand<R: Rng>(rng: &mut R) -> i16 {
41 rng.next_u32() as i16
42 }
43 }
44
45 impl Rand for i32 {
46 #[inline]
47 fn rand<R: Rng>(rng: &mut R) -> i32 {
48 rng.next_u32() as i32
49 }
50 }
51
52 impl Rand for i64 {
53 #[inline]
54 fn rand<R: Rng>(rng: &mut R) -> i64 {
55 rng.next_u64() as i64
56 }
57 }
58
59 impl Rand for uint {
60 #[inline]
61 fn rand<R: Rng>(rng: &mut R) -> uint {
62 if uint::BITS == 32 {
63 rng.gen::<u32>() as uint
64 } else {
65 rng.gen::<u64>() as uint
66 }
67 }
68 }
69
70 impl Rand for u8 {
71 #[inline]
72 fn rand<R: Rng>(rng: &mut R) -> u8 {
73 rng.next_u32() as u8
74 }
75 }
76
77 impl Rand for u16 {
78 #[inline]
79 fn rand<R: Rng>(rng: &mut R) -> u16 {
80 rng.next_u32() as u16
81 }
82 }
83
84 impl Rand for u32 {
85 #[inline]
86 fn rand<R: Rng>(rng: &mut R) -> u32 {
87 rng.next_u32()
88 }
89 }
90
91 impl Rand for u64 {
92 #[inline]
93 fn rand<R: Rng>(rng: &mut R) -> u64 {
94 rng.next_u64()
95 }
96 }
97
98 macro_rules! float_impls {
99 ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident) => {
100 mod $mod_name {
101 use {Rand, Rng, Open01, Closed01};
102
103 const SCALE: $ty = (1u64 << $mantissa_bits) as $ty;
104
105 impl Rand for $ty {
106 /// Generate a floating point number in the half-open
107 /// interval `[0,1)`.
108 ///
109 /// See `Closed01` for the closed interval `[0,1]`,
110 /// and `Open01` for the open interval `(0,1)`.
111 #[inline]
112 fn rand<R: Rng>(rng: &mut R) -> $ty {
113 rng.$method_name()
114 }
115 }
116 impl Rand for Open01<$ty> {
117 #[inline]
118 fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
119 // add a small amount (specifically 2 bits below
120 // the precision of f64/f32 at 1.0), so that small
121 // numbers are larger than 0, but large numbers
122 // aren't pushed to/above 1.
123 Open01(rng.$method_name() + 0.25 / SCALE)
124 }
125 }
126 impl Rand for Closed01<$ty> {
127 #[inline]
128 fn rand<R: Rng>(rng: &mut R) -> Closed01<$ty> {
129 // rescale so that 1.0 - epsilon becomes 1.0
130 // precisely.
131 Closed01(rng.$method_name() * SCALE / (SCALE - 1.0))
132 }
133 }
134 }
135 }
136 }
137 float_impls! { f64_rand_impls, f64, 53, next_f64 }
138 float_impls! { f32_rand_impls, f32, 24, next_f32 }
139
140 impl Rand for char {
141 #[inline]
142 fn rand<R: Rng>(rng: &mut R) -> char {
143 // a char is 21 bits
144 static CHAR_MASK: u32 = 0x001f_ffff;
145 loop {
146 // Rejection sampling. About 0.2% of numbers with at most
147 // 21-bits are invalid codepoints (surrogates), so this
148 // will succeed first go almost every time.
149 match char::from_u32(rng.next_u32() & CHAR_MASK) {
150 Some(c) => return c,
151 None => {}
152 }
153 }
154 }
155 }
156
157 impl Rand for bool {
158 #[inline]
159 fn rand<R: Rng>(rng: &mut R) -> bool {
160 rng.gen::<u8>() & 1 == 1
161 }
162 }
163
164 macro_rules! tuple_impl {
165 // use variables to indicate the arity of the tuple
166 ($($tyvar:ident),* ) => {
167 // the trailing commas are for the 1 tuple
168 impl<
169 $( $tyvar : Rand ),*
170 > Rand for ( $( $tyvar ),* , ) {
171
172 #[inline]
173 fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
174 (
175 // use the $tyvar's to get the appropriate number of
176 // repeats (they're not actually needed)
177 $(
178 _rng.gen::<$tyvar>()
179 ),*
180 ,
181 )
182 }
183 }
184 }
185 }
186
187 impl Rand for () {
188 #[inline]
189 fn rand<R: Rng>(_: &mut R) -> () { () }
190 }
191 tuple_impl!{A}
192 tuple_impl!{A, B}
193 tuple_impl!{A, B, C}
194 tuple_impl!{A, B, C, D}
195 tuple_impl!{A, B, C, D, E}
196 tuple_impl!{A, B, C, D, E, F}
197 tuple_impl!{A, B, C, D, E, F, G}
198 tuple_impl!{A, B, C, D, E, F, G, H}
199 tuple_impl!{A, B, C, D, E, F, G, H, I}
200 tuple_impl!{A, B, C, D, E, F, G, H, I, J}
201 tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
202 tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
203
204 impl<T:Rand> Rand for Option<T> {
205 #[inline]
206 fn rand<R: Rng>(rng: &mut R) -> Option<T> {
207 if rng.gen() {
208 Some(rng.gen())
209 } else {
210 None
211 }
212 }
213 }
214
215 #[cfg(test)]
216 mod tests {
217 use std::prelude::v1::*;
218 use std::rand::{Rng, thread_rng, Open01, Closed01};
219
220 struct ConstantRng(u64);
221 impl Rng for ConstantRng {
222 fn next_u32(&mut self) -> u32 {
223 let ConstantRng(v) = *self;
224 v as u32
225 }
226 fn next_u64(&mut self) -> u64 {
227 let ConstantRng(v) = *self;
228 v
229 }
230 }
231
232 #[test]
233 fn floating_point_edge_cases() {
234 // the test for exact equality is correct here.
235 assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0);
236 assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0);
237 }
238
239 #[test]
240 fn rand_open() {
241 // this is unlikely to catch an incorrect implementation that
242 // generates exactly 0 or 1, but it keeps it sane.
243 let mut rng = thread_rng();
244 for _ in range(0u, 1_000) {
245 // strict inequalities
246 let Open01(f) = rng.gen::<Open01<f64>>();
247 assert!(0.0 < f && f < 1.0);
248
249 let Open01(f) = rng.gen::<Open01<f32>>();
250 assert!(0.0 < f && f < 1.0);
251 }
252 }
253
254 #[test]
255 fn rand_closed() {
256 let mut rng = thread_rng();
257 for _ in range(0u, 1_000) {
258 // strict inequalities
259 let Closed01(f) = rng.gen::<Closed01<f64>>();
260 assert!(0.0 <= f && f <= 1.0);
261
262 let Closed01(f) = rng.gen::<Closed01<f32>>();
263 assert!(0.0 <= f && f <= 1.0);
264 }
265 }
266 }