@@ -246,14 +246,11 @@ pub trait UniformSampler: Sized {
246
246
/// Sample a single value uniformly from a range with inclusive lower bound
247
247
/// and exclusive upper bound `[low, high)`.
248
248
///
249
- /// Usually users should not call this directly but instead use
250
- /// `Uniform::sample_single`, which asserts that `low < high` before calling
251
- /// this.
252
- ///
253
- /// Via this method, implementations can provide a method optimized for
254
- /// sampling only a single value from the specified range. The default
255
- /// implementation simply calls `UniformSampler::new` then `sample` on the
256
- /// result.
249
+ /// By default this is implemented using
250
+ /// `UniformSampler::new(low, high).sample(rng)`. However, for some types
251
+ /// more optimal implementations for single usage may be provided via this
252
+ /// method (which is the case for integers and floats).
253
+ /// Results may not be identical.
257
254
fn sample_single < R : Rng + ?Sized , B1 , B2 > ( low : B1 , high : B2 , rng : & mut R )
258
255
-> Self :: X
259
256
where B1 : SampleBorrow < Self :: X > + Sized ,
@@ -309,31 +306,29 @@ impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed where Borrowed: Sampl
309
306
///
310
307
/// # Implementation notes
311
308
///
309
+ /// For simplicity, we use the same generic struct `UniformInt<X>` for all
310
+ /// integer types `X`. This gives us only one field type, `X`; to store unsigned
311
+ /// values of this size, we take use the fact that these conversions are no-ops.
312
+ ///
312
313
/// For a closed range, the number of possible numbers we should generate is
313
- /// `range = (high - low + 1)`. It is not possible to end up with a uniform
314
- /// distribution if we map *all* the random integers that can be generated to
315
- /// this range. We have to map integers from a `zone` that is a multiple of the
316
- /// range. The rest of the integers, that cause a bias, are rejected.
314
+ /// `range = (high - low + 1)`. To avoid bias, we must ensure that the size of
315
+ /// our sample space, `zone`, is a multiple of `range`; other values must be
316
+ /// rejected (by replacing with a new random sample).
317
317
///
318
- /// The problem with `range` is that to cover the full range of the type, it has
319
- /// to store `unsigned_max + 1`, which can't be represented. But if the range
320
- /// covers the full range of the type, no modulus is needed. A range of size 0
321
- /// can't exist, so we use that to represent this special case. Wrapping
322
- /// arithmetic even makes representing `unsigned_max + 1` as 0 simple.
318
+ /// As a special case, we use `range = 0` to represent the full range of the
319
+ /// result type (i.e. for `new_inclusive($ty::MIN, $ty::MAX)`).
323
320
///
324
- /// We don't calculate `zone` directly, but first calculate the number of
325
- /// integers to reject. To handle `unsigned_max + 1` not fitting in the type,
326
- /// we use:
327
- /// `ints_to_reject = (unsigned_max + 1) % range;`
328
- /// `ints_to_reject = (unsigned_max - range + 1) % range;`
321
+ /// The optimum `zone` is the largest product of `range` which fits in our
322
+ /// (unsigned) target type. We calculate this by calculating how many numbers we
323
+ /// must reject: `reject = (MAX + 1) % range = (MAX - range + 1) % range`. Any (large)
324
+ /// product of `range` will suffice, thus in `sample_single` we multiply by a
325
+ /// power of 2 via bit-shifting (faster but may cause more rejections).
329
326
///
330
- /// The smallest integer PRNGs generate is `u32`. That is why for small integer
331
- /// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization: don't pick the
332
- /// largest zone that can fit in the small type, but pick the largest zone that
333
- /// can fit in an `u32`. `ints_to_reject` is always less than half the size of
334
- /// the small integer. This means the first bit of `zone` is always 1, and so
335
- /// are all the other preceding bits of a larger integer. The easiest way to
336
- /// grow the `zone` for the larger type is to simply sign extend it.
327
+ /// The smallest integer PRNGs generate is `u32`. For 8- and 16-bit outputs we
328
+ /// use `u32` for our `zone` and samples (because it's not slower and because
329
+ /// it reduces the chance of having to reject a sample). In this case we cannot
330
+ /// store `zone` in the target type since it is too large, however we know
331
+ /// `ints_to_reject < range <= $unsigned::MAX`.
337
332
///
338
333
/// An alternative to using a modulus is widening multiply: After a widening
339
334
/// multiply by `range`, the result is in the high word. Then comparing the low
@@ -342,12 +337,11 @@ impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed where Borrowed: Sampl
342
337
pub struct UniformInt < X > {
343
338
low : X ,
344
339
range : X ,
345
- zone : X ,
340
+ z : X , // either ints_to_reject or zone depending on implementation
346
341
}
347
342
348
343
macro_rules! uniform_int_impl {
349
- ( $ty: ty, $signed: ty, $unsigned: ident,
350
- $i_large: ident, $u_large: ident) => {
344
+ ( $ty: ty, $unsigned: ident, $u_large: ident) => {
351
345
impl SampleUniform for $ty {
352
346
type Sampler = UniformInt <$ty>;
353
347
}
@@ -382,34 +376,30 @@ macro_rules! uniform_int_impl {
382
376
let high = * high_b. borrow( ) ;
383
377
assert!( low <= high,
384
378
"Uniform::new_inclusive called with `low > high`" ) ;
385
- let unsigned_max = :: core:: $unsigned :: MAX ;
379
+ let unsigned_max = :: core:: $u_large :: MAX ;
386
380
387
381
let range = high. wrapping_sub( low) . wrapping_add( 1 ) as $unsigned;
388
382
let ints_to_reject =
389
383
if range > 0 {
384
+ let range = range as $u_large;
390
385
( unsigned_max - range + 1 ) % range
391
386
} else {
392
387
0
393
388
} ;
394
- let zone = unsigned_max - ints_to_reject;
395
389
396
390
UniformInt {
397
391
low: low,
398
392
// These are really $unsigned values, but store as $ty:
399
393
range: range as $ty,
400
- zone : zone as $ty
394
+ z : ints_to_reject as $unsigned as $ty
401
395
}
402
396
}
403
397
404
398
fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> Self :: X {
405
399
let range = self . range as $unsigned as $u_large;
406
400
if range > 0 {
407
- // Grow `zone` to fit a type of at least 32 bits, by
408
- // sign-extending it (the first bit is always 1, so are all
409
- // the preceding bits of the larger type).
410
- // For types that already have the right size, all the
411
- // casting is a no-op.
412
- let zone = self . zone as $signed as $i_large as $u_large;
401
+ let unsigned_max = :: core:: $u_large:: MAX ;
402
+ let zone = unsigned_max - ( self . z as $unsigned as $u_large) ;
413
403
loop {
414
404
let v: $u_large = rng. gen ( ) ;
415
405
let ( hi, lo) = v. wmul( range) ;
@@ -431,7 +421,7 @@ macro_rules! uniform_int_impl {
431
421
let low = * low_b. borrow( ) ;
432
422
let high = * high_b. borrow( ) ;
433
423
assert!( low < high,
434
- "Uniform ::sample_single called with low >= high" ) ;
424
+ "UniformSampler ::sample_single: low >= high" ) ;
435
425
let range = high. wrapping_sub( low) as $unsigned as $u_large;
436
426
let zone =
437
427
if :: core:: $unsigned:: MAX <= :: core:: u16 :: MAX as $unsigned {
@@ -459,20 +449,20 @@ macro_rules! uniform_int_impl {
459
449
}
460
450
}
461
451
462
- uniform_int_impl ! { i8 , i8 , u8 , i32 , u32 }
463
- uniform_int_impl ! { i16 , i16 , u16 , i32 , u32 }
464
- uniform_int_impl ! { i32 , i32 , u32 , i32 , u32 }
465
- uniform_int_impl ! { i64 , i64 , u64 , i64 , u64 }
452
+ uniform_int_impl ! { i8 , u8 , u32 }
453
+ uniform_int_impl ! { i16 , u16 , u32 }
454
+ uniform_int_impl ! { i32 , u32 , u32 }
455
+ uniform_int_impl ! { i64 , u64 , u64 }
466
456
#[ cfg( all( rustc_1_26, not( target_os = "emscripten" ) ) ) ]
467
- uniform_int_impl ! { i128 , i128 , u128 , u128 , u128 }
468
- uniform_int_impl ! { isize , isize , usize , isize , usize }
469
- uniform_int_impl ! { u8 , i8 , u8 , i32 , u32 }
470
- uniform_int_impl ! { u16 , i16 , u16 , i32 , u32 }
471
- uniform_int_impl ! { u32 , i32 , u32 , i32 , u32 }
472
- uniform_int_impl ! { u64 , i64 , u64 , i64 , u64 }
473
- uniform_int_impl ! { usize , isize , usize , isize , usize }
457
+ uniform_int_impl ! { i128 , u128 , u128 }
458
+ uniform_int_impl ! { isize , usize , usize }
459
+ uniform_int_impl ! { u8 , u8 , u32 }
460
+ uniform_int_impl ! { u16 , u16 , u32 }
461
+ uniform_int_impl ! { u32 , u32 , u32 }
462
+ uniform_int_impl ! { u64 , u64 , u64 }
463
+ uniform_int_impl ! { usize , usize , usize }
474
464
#[ cfg( all( rustc_1_26, not( target_os = "emscripten" ) ) ) ]
475
- uniform_int_impl ! { u128 , u128 , u128 , i128 , u128 }
465
+ uniform_int_impl ! { u128 , u128 , u128 }
476
466
477
467
#[ cfg( all( feature = "simd_support" , feature = "nightly" ) ) ]
478
468
macro_rules! uniform_simd_int_impl {
@@ -534,13 +524,13 @@ macro_rules! uniform_simd_int_impl {
534
524
low: low,
535
525
// These are really $unsigned values, but store as $ty:
536
526
range: range. cast( ) ,
537
- zone : zone. cast( ) ,
527
+ z : zone. cast( ) ,
538
528
}
539
529
}
540
530
541
531
fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> Self :: X {
542
532
let range: $unsigned = self . range. cast( ) ;
543
- let zone: $unsigned = self . zone . cast( ) ;
533
+ let zone: $unsigned = self . z . cast( ) ;
544
534
545
535
// This might seem very slow, generating a whole new
546
536
// SIMD vector for every sample rejection. For most uses
@@ -736,7 +726,7 @@ macro_rules! uniform_float_impl {
736
726
let low = * low_b. borrow( ) ;
737
727
let high = * high_b. borrow( ) ;
738
728
assert!( low. all_lt( high) ,
739
- "Uniform ::sample_single called with low >= high" ) ;
729
+ "UniformSampler ::sample_single: low >= high" ) ;
740
730
let mut scale = high - low;
741
731
742
732
loop {
@@ -787,7 +777,7 @@ macro_rules! uniform_float_impl {
787
777
let mask = !scale. finite_mask( ) ;
788
778
if mask. any( ) {
789
779
assert!( low. all_finite( ) && high. all_finite( ) ,
790
- "Uniform::sample_single called with non-finite boundaries " ) ;
780
+ "Uniform::sample_single: low and high must be finite " ) ;
791
781
scale = scale. decrease_masked( mask) ;
792
782
}
793
783
}
0 commit comments