1
1
#[ doc = "Random number generation" ] ;
2
2
3
- export rng, extensions;
3
+ export rng, weighted , extensions;
4
4
5
5
enum rctx { }
6
6
@@ -17,44 +17,214 @@ iface rng {
17
17
fn next( ) -> u32;
18
18
}
19
19
20
+ #[ doc = "A value with a particular weight compared to other values" ]
21
+ type weighted < T > = { weight : uint , item: T } ;
22
+
20
23
#[ doc = "Extension methods for random number generators" ]
21
24
impl extensions for rng {
22
25
26
+ #[ doc = "Return a random int" ]
27
+ fn gen_int ( ) -> int {
28
+ self . gen_i64 ( ) as int
29
+ }
30
+
31
+ #[ doc = "Return an int randomly chosen from the range [start, end], \
32
+ failing if start > end"]
33
+ fn gen_int_from ( start : int , end : int ) -> int {
34
+ assert start <= end;
35
+ start + int:: abs ( self . gen_int ( ) % ( end - start + 1 ) )
36
+ }
37
+
38
+ #[ doc = "Return a random i8" ]
39
+ fn gen_i8 ( ) -> i8 {
40
+ self . next ( ) as i8
41
+ }
42
+
43
+ #[ doc = "Return a random i16" ]
44
+ fn gen_i16 ( ) -> i16 {
45
+ self . next ( ) as i16
46
+ }
47
+
48
+ #[ doc = "Return a random i32" ]
49
+ fn gen_i32 ( ) -> i32 {
50
+ self . next ( ) as i32
51
+ }
52
+
53
+ #[ doc = "Return a random i64" ]
54
+ fn gen_i64 ( ) -> i64 {
55
+ ( self . next ( ) as i64 << 32 ) | self . next ( ) as i64
56
+ }
57
+
58
+ #[ doc = "Return a random uint" ]
59
+ fn gen_uint ( ) -> uint {
60
+ self . gen_u64 ( ) as u64
61
+ }
62
+
63
+ #[ doc = "Return a uint randomly chosen from the range [start, end], \
64
+ failing if start > end"]
65
+ fn gen_uint_from ( start : uint , end : uint ) -> uint {
66
+ assert start <= end;
67
+ start + ( self . gen_uint ( ) % ( end - start + 1 u) )
68
+ }
69
+
70
+ #[ doc = "Return a random u8" ]
71
+ fn gen_u8 ( ) -> u8 {
72
+ self . next ( ) as u8
73
+ }
74
+
75
+ #[ doc = "Return a random u16" ]
76
+ fn gen_u16 ( ) -> u16 {
77
+ self . next ( ) as u16
78
+ }
79
+
80
+ #[ doc = "Return a random u32" ]
81
+ fn gen_u32 ( ) -> u32 {
82
+ self . next ( )
83
+ }
84
+
85
+ #[ doc = "Return a random u64" ]
86
+ fn gen_u64 ( ) -> u64 {
87
+ ( self . next ( ) as u64 << 32 ) | self . next ( ) as u64
88
+ }
89
+
23
90
#[ doc = "Return a random float" ]
24
91
fn gen_float ( ) -> float {
25
- let u1 = self . next ( ) as float ;
26
- let u2 = self . next ( ) as float ;
27
- let u3 = self . next ( ) as float ;
28
- let scale = u32:: max_value as float ;
29
- ret ( ( u1 / scale + u2) / scale + u3) / scale;
92
+ self . gen_f64 ( ) as float
30
93
}
31
94
32
- #[ doc = "Return a random string composed of A-Z, a-z, 0-9." ]
95
+ #[ doc = "Return a random f32" ]
96
+ fn gen_f32 ( ) -> f32 {
97
+ self . gen_f64 ( ) as f32
98
+ }
99
+
100
+ #[ doc = "Return a random f64" ]
101
+ fn gen_f64 ( ) -> f64 {
102
+ let u1 = self . next ( ) as f64 ;
103
+ let u2 = self . next ( ) as f64 ;
104
+ let u3 = self . next ( ) as f64 ;
105
+ let scale = u32:: max_value as f64 ;
106
+ ret ( ( u1 / scale + u2) / scale + u3) / scale;
107
+ }
108
+
109
+ #[ doc = "Return a random char" ]
110
+ fn gen_char ( ) -> char {
111
+ self . next ( ) as char
112
+ }
113
+
114
+ #[ doc = "Return a char randomly chosen from chars, failing if chars is \
115
+ empty"]
116
+ fn gen_char_from ( chars : str ) -> char {
117
+ assert !chars. is_empty ( ) ;
118
+ self . choose ( str:: chars ( chars) )
119
+ }
120
+
121
+ #[ doc = "Return a random bool" ]
122
+ fn gen_bool ( ) -> bool {
123
+ self . next ( ) & 1u32 == 1u32
124
+ }
125
+
126
+ #[ doc = "Return a bool with a 1 in n chance of true" ]
127
+ fn gen_weighted_bool ( n : uint ) -> bool {
128
+ if n == 0 u {
129
+ true
130
+ } else {
131
+ self . gen_uint_from ( 1 u, n) == 1 u
132
+ }
133
+ }
134
+
135
+ #[ doc = "Return a random string of the specified length composed of A-Z, \
136
+ a-z, 0-9"]
33
137
fn gen_str ( len : uint ) -> str {
34
138
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
35
139
"abcdefghijklmnopqrstuvwxyz" +
36
140
"0123456789" ;
37
141
let mut s = "" ;
38
142
let mut i = 0 u;
39
143
while ( i < len) {
40
- let n = self . next ( ) as uint % charset. len ( ) ;
41
- s = s + str:: from_char ( str:: char_at ( charset, n) ) ;
144
+ s = s + str:: from_char ( self . gen_char_from ( charset) ) ;
42
145
i += 1 u;
43
146
}
44
147
s
45
148
}
46
149
47
- #[ doc = "Return a random byte string. " ]
150
+ #[ doc = "Return a random byte string of the specified length " ]
48
151
fn gen_bytes ( len : uint ) -> [ u8 ] {
49
- let mut v = [ ] ;
50
- let mut i = 0 u;
51
- while i < len {
52
- let n = self . next ( ) as uint ;
53
- v += [ ( n % ( u8:: max_value as uint ) ) as u8 ] ;
54
- i += 1 u;
152
+ vec:: from_fn ( len) { |_i|
153
+ self . gen_u8 ( )
154
+ }
155
+ }
156
+
157
+ #[ doc = "Choose an item randomly, failing if values is empty" ]
158
+ fn choose < T : copy > ( values : [ T ] ) -> T {
159
+ self . choose_option ( values) . get ( )
160
+ }
161
+
162
+ #[ doc = "Choose some(item) randomly, returning none if values is empty" ]
163
+ fn choose_option < T : copy > ( values : [ T ] ) -> option < T > {
164
+ if values. is_empty ( ) {
165
+ none
166
+ } else {
167
+ some ( values[ self . gen_uint_from ( 0 u, values. len ( ) - 1 u) ] )
55
168
}
56
- v
57
169
}
170
+
171
+ #[ doc = "Choose an item respecting the relative weights, failing if \
172
+ the sum of the weights is 0"]
173
+ fn choose_weighted < T : copy > ( v : [ weighted < T > ] ) -> T {
174
+ self . choose_weighted_option ( v) . get ( )
175
+ }
176
+
177
+ #[ doc = "Choose some(item) respecting the relative weights, returning \
178
+ none if the sum of the weights is 0"]
179
+ fn choose_weighted_option < T : copy > ( v : [ weighted < T > ] ) -> option < T > {
180
+ let mut total = 0 u;
181
+ for v. each { |item|
182
+ total += item. weight;
183
+ }
184
+ if total == 0 u {
185
+ ret none;
186
+ }
187
+ let chosen = self . gen_uint_from ( 0 u, total - 1 u) ;
188
+ let mut so_far = 0 u;
189
+ for v. each { |item|
190
+ so_far += item. weight;
191
+ if so_far > chosen {
192
+ ret some ( item. item ) ;
193
+ }
194
+ }
195
+ unreachable ( ) ;
196
+ }
197
+
198
+ #[ doc = "Return a vec containing copies of the items, in order, where \
199
+ the weight of the item determines how many copies there are"]
200
+ fn weighted_vec < T : copy > ( v : [ weighted < T > ] ) -> [ T ] {
201
+ let mut r = [ ] ;
202
+ for v. each { |item|
203
+ uint:: range( 0 u, item. weight) { |_i|
204
+ r += [ item. item ] ;
205
+ }
206
+ }
207
+ r
208
+ }
209
+
210
+ #[ doc = "Shuffle a vec" ]
211
+ fn shuffle < T : copy > ( values : [ T ] ) -> [ T ] {
212
+ let mut m = vec:: to_mut ( values) ;
213
+ self . shuffle_mut ( m) ;
214
+ ret vec:: from_mut ( m) ;
215
+ }
216
+
217
+ #[ doc = "Shuffle a mutable vec in place" ]
218
+ fn shuffle_mut < T > ( & values: [ mut T ] ) {
219
+ let mut i = values. len ( ) ;
220
+ while i >= 2 u {
221
+ // invariant: elements with index >= i have been locked in place.
222
+ i -= 1 u;
223
+ // lock element i in place.
224
+ vec:: swap ( values, i, self . gen_uint_from ( 0 u, i) ) ;
225
+ }
226
+ }
227
+
58
228
}
59
229
60
230
#[ doc = "Create a random number generator" ]
@@ -72,27 +242,33 @@ fn rng() -> rng {
72
242
mod tests {
73
243
74
244
#[ test]
75
- fn test ( ) {
76
- let r1 = rand:: rng ( ) ;
77
- log ( debug, r1. next ( ) ) ;
78
- log ( debug, r1. next ( ) ) ;
79
- {
80
- let r2 = rand:: rng ( ) ;
81
- log ( debug, r1. next ( ) ) ;
82
- log ( debug, r2. next ( ) ) ;
83
- log ( debug, r1. next ( ) ) ;
84
- log ( debug, r1. next ( ) ) ;
85
- log ( debug, r2. next ( ) ) ;
86
- log ( debug, r2. next ( ) ) ;
87
- log ( debug, r1. next ( ) ) ;
88
- log ( debug, r1. next ( ) ) ;
89
- log ( debug, r1. next ( ) ) ;
90
- log ( debug, r2. next ( ) ) ;
91
- log ( debug, r2. next ( ) ) ;
92
- log ( debug, r2. next ( ) ) ;
93
- }
94
- log ( debug, r1. next ( ) ) ;
95
- log ( debug, r1. next ( ) ) ;
245
+ fn gen_int_from ( ) {
246
+ let r = rand:: rng ( ) ;
247
+ let a = r. gen_int_from ( -3 , 42 ) ;
248
+ assert a >= -3 && a <= 42 ;
249
+ assert r. gen_int_from ( 0 , 0 ) == 0 ;
250
+ assert r. gen_int_from ( -12 , -12 ) == -12 ;
251
+ }
252
+
253
+ #[ test]
254
+ #[ should_fail]
255
+ fn gen_int_from_fail ( ) {
256
+ rand:: rng ( ) . gen_int_from ( 5 , -2 ) ;
257
+ }
258
+
259
+ #[ test]
260
+ fn gen_uint_from ( ) {
261
+ let r = rand:: rng ( ) ;
262
+ let a = r. gen_uint_from ( 3 u, 42 u) ;
263
+ assert a >= 3 u && a <= 42 u;
264
+ assert r. gen_uint_from ( 0 u, 0 u) == 0 u;
265
+ assert r. gen_uint_from ( 12 u, 12 u) == 12 u;
266
+ }
267
+
268
+ #[ test]
269
+ #[ should_fail]
270
+ fn gen_uint_from_fail ( ) {
271
+ rand:: rng ( ) . gen_uint_from ( 5 u, 2 u) ;
96
272
}
97
273
98
274
#[ test]
@@ -103,6 +279,13 @@ mod tests {
103
279
log ( debug, ( a, b) ) ;
104
280
}
105
281
282
+ #[ test]
283
+ fn gen_weighted_bool ( ) {
284
+ let r = rand:: rng ( ) ;
285
+ assert r. gen_weighted_bool ( 0 u) == true ;
286
+ assert r. gen_weighted_bool ( 1 u) == true ;
287
+ }
288
+
106
289
#[ test]
107
290
fn gen_str ( ) {
108
291
let r = rand:: rng ( ) ;
@@ -121,6 +304,60 @@ mod tests {
121
304
assert r. gen_bytes ( 10 u) . len ( ) == 10 u;
122
305
assert r. gen_bytes ( 16 u) . len ( ) == 16 u;
123
306
}
307
+
308
+ #[ test]
309
+ fn choose ( ) {
310
+ let r = rand:: rng ( ) ;
311
+ assert r. choose ( [ 1 , 1 , 1 ] ) == 1 ;
312
+ }
313
+
314
+ #[ test]
315
+ fn choose_option ( ) {
316
+ let r = rand:: rng ( ) ;
317
+ assert r. choose_option ( [ ] ) == none :: < int > ;
318
+ assert r. choose_option ( [ 1 , 1 , 1 ] ) == some ( 1 ) ;
319
+ }
320
+
321
+ #[ test]
322
+ fn choose_weighted ( ) {
323
+ let r = rand:: rng ( ) ;
324
+ assert r. choose_weighted ( [ { weight: 1 u, item: 42 } ] ) == 42 ;
325
+ assert r. choose_weighted ( [
326
+ { weight: 0 u, item: 42 } ,
327
+ { weight: 1 u, item: 43 }
328
+ ] ) == 43 ;
329
+ }
330
+
331
+ #[ test]
332
+ fn choose_weighted_option ( ) {
333
+ let r = rand:: rng ( ) ;
334
+ assert r. choose_weighted_option ( [ { weight: 1 u, item: 42 } ] ) == some ( 42 ) ;
335
+ assert r. choose_weighted_option ( [
336
+ { weight: 0 u, item: 42 } ,
337
+ { weight: 1 u, item: 43 }
338
+ ] ) == some ( 43 ) ;
339
+ assert r. choose_weighted_option ( [ ] ) == none :: < int > ;
340
+ }
341
+
342
+ #[ test]
343
+ fn weighted_vec ( ) {
344
+ let r = rand:: rng ( ) ;
345
+ let empty: [ int ] = [ ] ;
346
+ assert r. weighted_vec ( [ ] ) == empty;
347
+ assert r. weighted_vec ( [
348
+ { weight: 0 u, item: 3 u} ,
349
+ { weight: 1 u, item: 2 u} ,
350
+ { weight: 2 u, item: 1 u}
351
+ ] ) == [ 2 u, 1 u, 1 u] ;
352
+ }
353
+
354
+ #[ test]
355
+ fn shuffle ( ) {
356
+ let r = rand:: rng ( ) ;
357
+ let empty: [ int ] = [ ] ;
358
+ assert r. shuffle ( [ ] ) == empty;
359
+ assert r. shuffle ( [ 1 , 1 , 1 ] ) == [ 1 , 1 , 1 ] ;
360
+ }
124
361
}
125
362
126
363
0 commit comments