50
50
//!
51
51
//! At a minimum, the back-end needs to store any parameters needed for sampling
52
52
//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`.
53
- //! The example below merely wraps another back-end.
53
+ //! Those methods should include an assert to check the range is valid (i.e.
54
+ //! `low < high`). The example below merely wraps another back-end.
54
55
//!
55
56
//! ```
56
57
//! use rand::prelude::*;
57
58
//! use rand::distributions::uniform::{Uniform, SampleUniform,
58
59
//! UniformSampler, UniformFloat};
59
60
//!
60
- //! #[derive(Clone, Copy, PartialEq, PartialOrd)]
61
61
//! struct MyF32(f32);
62
62
//!
63
63
//! #[derive(Clone, Copy, Debug)]
64
64
//! struct UniformMyF32 {
65
65
//! inner: UniformFloat<f32>,
66
66
//! }
67
+ //!
67
68
//! impl UniformSampler for UniformMyF32 {
68
69
//! type X = MyF32;
69
70
//! fn new(low: Self::X, high: Self::X) -> Self {
@@ -162,21 +163,18 @@ impl<X: SampleUniform> Uniform<X> {
162
163
/// Create a new `Uniform` instance which samples uniformly from the half
163
164
/// open range `[low, high)` (excluding `high`). Panics if `low >= high`.
164
165
pub fn new ( low : X , high : X ) -> Uniform < X > {
165
- assert ! ( low < high, "Uniform::new called with `low >= high`" ) ;
166
166
Uniform { inner : X :: Sampler :: new ( low, high) }
167
167
}
168
168
169
169
/// Create a new `Uniform` instance which samples uniformly from the closed
170
170
/// range `[low, high]` (inclusive). Panics if `low > high`.
171
171
pub fn new_inclusive ( low : X , high : X ) -> Uniform < X > {
172
- assert ! ( low <= high, "Uniform::new_inclusive called with `low > high`" ) ;
173
172
Uniform { inner : X :: Sampler :: new_inclusive ( low, high) }
174
173
}
175
174
176
175
/// Sample a single value uniformly from `[low, high)`.
177
176
/// Panics if `low >= high`.
178
177
pub fn sample_single < R : Rng + ?Sized > ( low : X , high : X , rng : & mut R ) -> X {
179
- assert ! ( low < high, "Uniform::sample_single called with low >= high" ) ;
180
178
X :: Sampler :: sample_single ( low, high, rng)
181
179
}
182
180
}
@@ -196,7 +194,7 @@ impl<X: SampleUniform> Distribution<X> for Uniform<X> {
196
194
/// [`UniformSampler`]: trait.UniformSampler.html
197
195
/// [module documentation]: index.html
198
196
/// [`Uniform`]: struct.Uniform.html
199
- pub trait SampleUniform : PartialOrd + Sized {
197
+ pub trait SampleUniform : Sized {
200
198
/// The `UniformSampler` implementation supporting type `X`.
201
199
type Sampler : UniformSampler < X = Self > ;
202
200
}
@@ -214,7 +212,7 @@ pub trait SampleUniform: PartialOrd+Sized {
214
212
/// [`sample_single`]: trait.UniformSampler.html#method.sample_single
215
213
pub trait UniformSampler : Sized {
216
214
/// The type sampled by this implementation.
217
- type X : PartialOrd ;
215
+ type X ;
218
216
219
217
/// Construct self, with inclusive lower bound and exclusive upper bound
220
218
/// `[low, high)`.
@@ -252,6 +250,17 @@ pub trait UniformSampler: Sized {
252
250
}
253
251
}
254
252
253
+ impl < X : SampleUniform > From < :: core:: ops:: Range < X > > for Uniform < X > {
254
+ fn from ( r : :: core:: ops:: Range < X > ) -> Uniform < X > {
255
+ Uniform :: new ( r. start , r. end )
256
+ }
257
+ }
258
+
259
+ ////////////////////////////////////////////////////////////////////////////////
260
+
261
+ // What follows are all back-ends.
262
+
263
+
255
264
/// The back-end implementing [`UniformSampler`] for integer types.
256
265
///
257
266
/// Unless you are implementing [`UniformSampler`] for your own type, this type
@@ -278,17 +287,12 @@ pub trait UniformSampler: Sized {
278
287
/// `ints_to_reject = (unsigned_max - range + 1) % range;`
279
288
///
280
289
/// The smallest integer PRNGs generate is `u32`. That is why for small integer
281
- /// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimisation : don't pick the
290
+ /// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization : don't pick the
282
291
/// largest zone that can fit in the small type, but pick the largest zone that
283
- /// can fit in an `u32`. This improves the chance to get a random integer that
284
- /// fits in the zone to 998 in 1000 in the worst case.
285
- ///
286
- /// There is a problem however: we can't store the acceptable `zone` of such a
287
- /// larger type in `UniformInt`, which only holds values with the size of the
288
- /// type. `ints_to_reject` is always less than half the size of the small
289
- /// integer. For an `u8` it only ever uses 7 bits. This means that all but the
290
- /// last 7 bits of `zone` are always 1's (or 15 in the case of `u16`). So
291
- /// nothing is lost by trucating `zone`.
292
+ /// can fit in an `u32`. `ints_to_reject` is always less than half the size of
293
+ /// the small integer. This means the first bit of `zone` is always 1, and so
294
+ /// are all the other preceding bits of a larger integer. The easiest way to
295
+ /// grow the `zone` for the larger type is to simply sign extend it.
292
296
///
293
297
/// An alternative to using a modulus is widening multiply: After a widening
294
298
/// multiply by `range`, the result is in the high word. Then comparing the low
@@ -321,17 +325,18 @@ macro_rules! uniform_int_impl {
321
325
#[ inline] // if the range is constant, this helps LLVM to do the
322
326
// calculations at compile-time.
323
327
fn new( low: Self :: X , high: Self :: X ) -> Self {
328
+ assert!( low < high, "Uniform::new called with `low >= high`" ) ;
324
329
UniformSampler :: new_inclusive( low, high - 1 )
325
330
}
326
331
327
332
#[ inline] // if the range is constant, this helps LLVM to do the
328
333
// calculations at compile-time.
329
334
fn new_inclusive( low: Self :: X , high: Self :: X ) -> Self {
330
- let unsigned_max: $u_large = :: core:: $u_large:: MAX ;
335
+ assert!( low <= high,
336
+ "Uniform::new_inclusive called with `low > high`" ) ;
337
+ let unsigned_max = :: core:: $unsigned:: MAX ;
331
338
332
- let range = ( high as $u_large)
333
- . wrapping_sub( low as $u_large)
334
- . wrapping_add( 1 ) ;
339
+ let range = high. wrapping_sub( low) . wrapping_add( 1 ) as $unsigned;
335
340
let ints_to_reject =
336
341
if range > 0 {
337
342
( unsigned_max - range + 1 ) % range
@@ -351,9 +356,9 @@ macro_rules! uniform_int_impl {
351
356
fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> Self :: X {
352
357
let range = self . range as $unsigned as $u_large;
353
358
if range > 0 {
354
- // Some casting to recover the trucated bits of `zone`:
355
- // First bit-cast to a signed int. Next sign-extend to the
356
- // larger type. Then bit-cast to unsigned .
359
+ // Grow `zone` to fit a type of at least 32 bits, by
360
+ // sign-extending it (the first bit is always 1, so are all
361
+ // the preceding bits of the larger type) .
357
362
// For types that already have the right size, all the
358
363
// casting is a no-op.
359
364
let zone = self . zone as $signed as $i_large as $u_large;
@@ -374,8 +379,9 @@ macro_rules! uniform_int_impl {
374
379
high: Self :: X ,
375
380
rng: & mut R ) -> Self :: X
376
381
{
377
- let range = ( high as $u_large)
378
- . wrapping_sub( low as $u_large) ;
382
+ assert!( low < high,
383
+ "Uniform::sample_single called with low >= high" ) ;
384
+ let range = high. wrapping_sub( low) as $unsigned as $u_large;
379
385
let zone =
380
386
if :: core:: $unsigned:: MAX <= :: core:: u16 :: MAX as $unsigned {
381
387
// Using a modulus is faster than the approximation for
@@ -401,12 +407,6 @@ macro_rules! uniform_int_impl {
401
407
}
402
408
}
403
409
404
- impl < X : SampleUniform > From < :: core:: ops:: Range < X > > for Uniform < X > {
405
- fn from ( r : :: core:: ops:: Range < X > ) -> Uniform < X > {
406
- Uniform :: new ( r. start , r. end )
407
- }
408
- }
409
-
410
410
uniform_int_impl ! { i8 , i8 , u8 , i32 , u32 }
411
411
uniform_int_impl ! { i16 , i16 , u16 , i32 , u32 }
412
412
uniform_int_impl ! { i32 , i32 , u32 , i32 , u32 }
@@ -442,7 +442,6 @@ macro_rules! wmul_impl {
442
442
}
443
443
}
444
444
}
445
-
446
445
wmul_impl ! { u8 , u16 , 8 }
447
446
wmul_impl ! { u16 , u32 , 16 }
448
447
wmul_impl ! { u32 , u64 , 32 }
@@ -481,13 +480,11 @@ macro_rules! wmul_impl_large {
481
480
}
482
481
}
483
482
}
484
-
485
483
#[ cfg( not( feature = "i128_support" ) ) ]
486
484
wmul_impl_large ! { u64 , 32 }
487
485
#[ cfg( feature = "i128_support" ) ]
488
486
wmul_impl_large ! { u128 , 64 }
489
487
490
-
491
488
macro_rules! wmul_impl_usize {
492
489
( $ty: ty) => {
493
490
impl WideningMultiply for usize {
@@ -501,7 +498,6 @@ macro_rules! wmul_impl_usize {
501
498
}
502
499
}
503
500
}
504
-
505
501
#[ cfg( target_pointer_width = "32" ) ]
506
502
wmul_impl_usize ! { u32 }
507
503
#[ cfg( target_pointer_width = "64" ) ]
@@ -550,6 +546,7 @@ macro_rules! uniform_float_impl {
550
546
type X = $ty;
551
547
552
548
fn new( low: Self :: X , high: Self :: X ) -> Self {
549
+ assert!( low < high, "Uniform::new called with `low >= high`" ) ;
553
550
let scale = high - low;
554
551
let offset = low - scale;
555
552
UniformFloat {
@@ -559,7 +556,14 @@ macro_rules! uniform_float_impl {
559
556
}
560
557
561
558
fn new_inclusive( low: Self :: X , high: Self :: X ) -> Self {
562
- UniformSampler :: new( low, high)
559
+ assert!( low <= high,
560
+ "Uniform::new_inclusive called with `low > high`" ) ;
561
+ let scale = high - low;
562
+ let offset = low - scale;
563
+ UniformFloat {
564
+ scale: scale,
565
+ offset: offset,
566
+ }
563
567
}
564
568
565
569
fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> Self :: X {
@@ -577,6 +581,8 @@ macro_rules! uniform_float_impl {
577
581
fn sample_single<R : Rng + ?Sized >( low: Self :: X ,
578
582
high: Self :: X ,
579
583
rng: & mut R ) -> Self :: X {
584
+ assert!( low < high,
585
+ "Uniform::sample_single called with low >= high" ) ;
580
586
let scale = high - low;
581
587
let offset = low - scale;
582
588
// Generate a value in the range [1, 2)
@@ -593,7 +599,9 @@ macro_rules! uniform_float_impl {
593
599
uniform_float_impl ! { f32 , 32 - 23 , next_u32 }
594
600
uniform_float_impl ! { f64 , 64 - 52 , next_u64 }
595
601
596
- /// Implementation of [`UniformSampler`] for `Duration`.
602
+
603
+
604
+ /// The back-end implementing [`UniformSampler`] for `Duration`.
597
605
///
598
606
/// Unless you are implementing [`UniformSampler`] for your own types, this type
599
607
/// should not be used directly, use [`Uniform`] instead.
@@ -630,11 +638,13 @@ impl UniformSampler for UniformDuration {
630
638
631
639
#[ inline]
632
640
fn new ( low : Duration , high : Duration ) -> UniformDuration {
641
+ assert ! ( low < high, "Uniform::new called with `low >= high`" ) ;
633
642
UniformDuration :: new_inclusive ( low, high - Duration :: new ( 0 , 1 ) )
634
643
}
635
644
636
645
#[ inline]
637
646
fn new_inclusive ( low : Duration , high : Duration ) -> UniformDuration {
647
+ assert ! ( low <= high, "Uniform::new_inclusive called with `low > high`" ) ;
638
648
let size = high - low;
639
649
let nanos = size
640
650
. as_secs ( )
0 commit comments