1
- // Copyright 2018 Developers of the Rand project.
1
+ // Copyright 2018-2020 Developers of the Rand project.
2
2
// Copyright 2017 The Rust Project Developers.
3
3
//
4
4
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
34
34
//! let side = Uniform::new(-10.0, 10.0);
35
35
//!
36
36
//! // sample between 1 and 10 points
37
- //! for _ in 0..rng.gen_range(1, 11 ) {
37
+ //! for _ in 0..rng.gen_range(1..=10 ) {
38
38
//! // sample a point from the square with sides -10 - 10 in two dimensions
39
39
//! let (x, y) = (rng.sample(side), rng.sample(side));
40
40
//! println!("Point: {}, {}", x, y);
105
105
106
106
#[ cfg( not( feature = "std" ) ) ] use core:: time:: Duration ;
107
107
#[ cfg( feature = "std" ) ] use std:: time:: Duration ;
108
+ use core:: ops:: { Range , RangeInclusive } ;
108
109
109
110
use crate :: distributions:: float:: IntoFloat ;
110
111
use crate :: distributions:: utils:: { BoolAsSIMD , FloatAsSIMD , FloatSIMDUtils , WideningMultiply } ;
111
112
use crate :: distributions:: Distribution ;
112
- use crate :: Rng ;
113
+ use crate :: { Rng , RngCore } ;
113
114
114
115
#[ cfg( not( feature = "std" ) ) ]
115
116
#[ allow( unused_imports) ] // rustc doesn't detect that this is actually used
@@ -124,7 +125,8 @@ use serde::{Serialize, Deserialize};
124
125
///
125
126
/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform
126
127
/// distribution sampling from the given range; these functions may do extra
127
- /// work up front to make sampling of multiple values faster.
128
+ /// work up front to make sampling of multiple values faster. If only one sample
129
+ /// from the range is required, [`Rng::gen_range`] can be more efficient.
128
130
///
129
131
/// When sampling from a constant range, many calculations can happen at
130
132
/// compile-time and all methods should be fast; for floating-point ranges and
@@ -139,27 +141,35 @@ use serde::{Serialize, Deserialize};
139
141
/// are of lower quality than the high bits.
140
142
///
141
143
/// Implementations must sample in `[low, high)` range for
142
- /// `Uniform::new(low, high)`, i.e., excluding `high`. In particular care must
144
+ /// `Uniform::new(low, high)`, i.e., excluding `high`. In particular, care must
143
145
/// be taken to ensure that rounding never results values `< low` or `>= high`.
144
146
///
145
147
/// # Example
146
148
///
147
149
/// ```
148
150
/// use rand::distributions::{Distribution, Uniform};
149
151
///
150
- /// fn main() {
151
- /// let between = Uniform::from(10..10000);
152
- /// let mut rng = rand::thread_rng();
153
- /// let mut sum = 0;
154
- /// for _ in 0..1000 {
155
- /// sum += between.sample(&mut rng);
156
- /// }
157
- /// println!("{}", sum);
152
+ /// let between = Uniform::from(10..10000);
153
+ /// let mut rng = rand::thread_rng();
154
+ /// let mut sum = 0;
155
+ /// for _ in 0..1000 {
156
+ /// sum += between.sample(&mut rng);
158
157
/// }
158
+ /// println!("{}", sum);
159
+ /// ```
160
+ ///
161
+ /// For a single sample, [`Rng::gen_range`] may be prefered:
162
+ ///
163
+ /// ```
164
+ /// use rand::Rng;
165
+ ///
166
+ /// let mut rng = rand::thread_rng();
167
+ /// println!("{}", rng.gen_range(0..10));
159
168
/// ```
160
169
///
161
170
/// [`new`]: Uniform::new
162
171
/// [`new_inclusive`]: Uniform::new_inclusive
172
+ /// [`Rng::gen_range`]: Rng::gen_range
163
173
#[ derive( Clone , Copy , Debug ) ]
164
174
#[ cfg_attr( feature = "serde1" , derive( Serialize , Deserialize ) ) ]
165
175
pub struct Uniform < X : SampleUniform > ( X :: Sampler ) ;
@@ -287,18 +297,19 @@ pub trait UniformSampler: Sized {
287
297
}
288
298
}
289
299
290
- impl < X : SampleUniform > From < :: core :: ops :: Range < X > > for Uniform < X > {
300
+ impl < X : SampleUniform > From < Range < X > > for Uniform < X > {
291
301
fn from ( r : :: core:: ops:: Range < X > ) -> Uniform < X > {
292
302
Uniform :: new ( r. start , r. end )
293
303
}
294
304
}
295
305
296
- impl < X : SampleUniform > From < :: core :: ops :: RangeInclusive < X > > for Uniform < X > {
306
+ impl < X : SampleUniform > From < RangeInclusive < X > > for Uniform < X > {
297
307
fn from ( r : :: core:: ops:: RangeInclusive < X > ) -> Uniform < X > {
298
308
Uniform :: new_inclusive ( r. start ( ) , r. end ( ) )
299
309
}
300
310
}
301
311
312
+
302
313
/// Helper trait similar to [`Borrow`] but implemented
303
314
/// only for SampleUniform and references to SampleUniform in
304
315
/// order to resolve ambiguity issues.
@@ -327,6 +338,43 @@ where Borrowed: SampleUniform
327
338
}
328
339
}
329
340
341
+ /// Range that supports generating a single sample efficiently.
342
+ ///
343
+ /// Any type implementing this trait can be used to specify the sampled range
344
+ /// for `Rng::gen_range`.
345
+ pub trait SampleRange < T > {
346
+ /// Generate a sample from the given range.
347
+ fn sample_single < R : RngCore + ?Sized > ( self , rng : & mut R ) -> T ;
348
+
349
+ /// Check whether the range is empty.
350
+ fn is_empty ( & self ) -> bool ;
351
+ }
352
+
353
+ impl < T : SampleUniform + PartialOrd > SampleRange < T > for Range < T > {
354
+ #[ inline]
355
+ fn sample_single < R : RngCore + ?Sized > ( self , rng : & mut R ) -> T {
356
+ T :: Sampler :: sample_single ( self . start , self . end , rng)
357
+ }
358
+
359
+ #[ inline]
360
+ fn is_empty ( & self ) -> bool {
361
+ !( self . start < self . end )
362
+ }
363
+ }
364
+
365
+ impl < T : SampleUniform + PartialOrd > SampleRange < T > for RangeInclusive < T > {
366
+ #[ inline]
367
+ fn sample_single < R : RngCore + ?Sized > ( self , rng : & mut R ) -> T {
368
+ T :: Sampler :: sample_single_inclusive ( self . start ( ) , self . end ( ) , rng)
369
+ }
370
+
371
+ #[ inline]
372
+ fn is_empty ( & self ) -> bool {
373
+ !( self . start ( ) <= self . end ( ) )
374
+ }
375
+ }
376
+
377
+
330
378
////////////////////////////////////////////////////////////////////////////////
331
379
332
380
// What follows are all back-ends.
@@ -425,7 +473,7 @@ macro_rules! uniform_int_impl {
425
473
} ;
426
474
427
475
UniformInt {
428
- low: low ,
476
+ low,
429
477
// These are really $unsigned values, but store as $ty:
430
478
range: range as $ty,
431
479
z: ints_to_reject as $unsigned as $ty,
@@ -570,7 +618,7 @@ macro_rules! uniform_simd_int_impl {
570
618
let zone = unsigned_max - ints_to_reject;
571
619
572
620
UniformInt {
573
- low: low ,
621
+ low,
574
622
// These are really $unsigned values, but store as $ty:
575
623
range: range. cast( ) ,
576
624
z: zone. cast( ) ,
@@ -985,7 +1033,7 @@ impl UniformSampler for UniformDuration {
985
1033
max_nanos,
986
1034
secs,
987
1035
} => {
988
- // constant folding means this is at least as fast as `gen_range `
1036
+ // constant folding means this is at least as fast as `Rng::sample(Range) `
989
1037
let nano_range = Uniform :: new ( 0 , 1_000_000_000 ) ;
990
1038
loop {
991
1039
let s = secs. sample ( rng) ;
@@ -1112,7 +1160,7 @@ mod tests {
1112
1160
}
1113
1161
1114
1162
for _ in 0 ..1000 {
1115
- let v: $ty = rng . gen_range ( low, high) ;
1163
+ let v = < $ty as SampleUniform > :: Sampler :: sample_single ( low, high, & mut rng ) ;
1116
1164
assert!( $le( low, v) && $lt( v, high) ) ;
1117
1165
}
1118
1166
}
@@ -1194,7 +1242,8 @@ mod tests {
1194
1242
assert!( low_scalar <= v && v < high_scalar) ;
1195
1243
let v = rng. sample( my_incl_uniform) . extract( lane) ;
1196
1244
assert!( low_scalar <= v && v <= high_scalar) ;
1197
- let v = rng. gen_range( low, high) . extract( lane) ;
1245
+ let v = <$ty as SampleUniform >:: Sampler
1246
+ :: sample_single( low, high, & mut rng) . extract( lane) ;
1198
1247
assert!( low_scalar <= v && v < high_scalar) ;
1199
1248
}
1200
1249
@@ -1205,7 +1254,9 @@ mod tests {
1205
1254
1206
1255
assert_eq!( zero_rng. sample( my_uniform) . extract( lane) , low_scalar) ;
1207
1256
assert_eq!( zero_rng. sample( my_incl_uniform) . extract( lane) , low_scalar) ;
1208
- assert_eq!( zero_rng. gen_range( low, high) . extract( lane) , low_scalar) ;
1257
+ assert_eq!( <$ty as SampleUniform >:: Sampler
1258
+ :: sample_single( low, high, & mut zero_rng)
1259
+ . extract( lane) , low_scalar) ;
1209
1260
assert!( max_rng. sample( my_uniform) . extract( lane) < high_scalar) ;
1210
1261
assert!( max_rng. sample( my_incl_uniform) . extract( lane) <= high_scalar) ;
1211
1262
@@ -1218,7 +1269,9 @@ mod tests {
1218
1269
( -1i64 << $bits_shifted) as u64 ,
1219
1270
) ;
1220
1271
assert!(
1221
- lowering_max_rng. gen_range( low, high) . extract( lane) < high_scalar
1272
+ <$ty as SampleUniform >:: Sampler
1273
+ :: sample_single( low, high, & mut lowering_max_rng)
1274
+ . extract( lane) < high_scalar
1222
1275
) ;
1223
1276
}
1224
1277
}
@@ -1266,7 +1319,7 @@ mod tests {
1266
1319
use std:: panic:: catch_unwind;
1267
1320
fn range < T : SampleUniform > ( low : T , high : T ) {
1268
1321
let mut rng = crate :: test:: rng ( 253 ) ;
1269
- rng . gen_range ( low, high) ;
1322
+ T :: Sampler :: sample_single ( low, high, & mut rng ) ;
1270
1323
}
1271
1324
1272
1325
macro_rules! t {
0 commit comments