@@ -288,17 +288,12 @@ impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {
288288/// `ints_to_reject = (unsigned_max - range + 1) % range;`
289289///
290290/// The smallest integer PRNGs generate is `u32`. That is why for small integer
291- /// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimisation : don't pick the
291+ /// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization : don't pick the
292292/// largest zone that can fit in the small type, but pick the largest zone that
293- /// can fit in an `u32`. This improves the chance to get a random integer that
294- /// fits in the zone to 998 in 1000 in the worst case.
295- ///
296- /// There is a problem however: we can't store the acceptable `zone` of such a
297- /// larger type in `UniformInt`, which only holds values with the size of the
298- /// type. `ints_to_reject` is always less than half the size of the small
299- /// integer. For an `u8` it only ever uses 7 bits. This means that all but the
300- /// last 7 bits of `zone` are always 1's (or 15 in the case of `u16`). So
301- /// nothing is lost by trucating `zone`.
293+ /// can fit in an `u32`. `ints_to_reject` is always less than half the size of
294+ /// the small integer. This means the first bit of `zone` is always 1, and so
295+ /// are all the other preceding bits of a larger integer. The easiest way to
296+ /// grow the `zone` for the larger type is to simply sign extend it.
302297///
303298/// An alternative to using a modulus is widening multiply: After a widening
304299/// multiply by `range`, the result is in the high word. Then comparing the low
@@ -341,11 +336,9 @@ macro_rules! uniform_int_impl {
341336 fn new_inclusive( low: Self :: X , high: Self :: X ) -> Self {
342337 assert!( low <= high,
343338 "Uniform::new_inclusive called with `low > high`" ) ;
344- let unsigned_max: $u_large = :: core:: $u_large :: MAX ;
339+ let unsigned_max = :: core:: $unsigned :: MAX ;
345340
346- let range = ( high as $u_large)
347- . wrapping_sub( low as $u_large)
348- . wrapping_add( 1 ) ;
341+ let range = high. wrapping_sub( low) . wrapping_add( 1 ) as $unsigned;
349342 let ints_to_reject =
350343 if range > 0 {
351344 ( unsigned_max - range + 1 ) % range
@@ -365,9 +358,9 @@ macro_rules! uniform_int_impl {
365358 fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> Self :: X {
366359 let range = self . range as $unsigned as $u_large;
367360 if range > 0 {
368- // Some casting to recover the trucated bits of `zone`:
369- // First bit-cast to a signed int. Next sign-extend to the
370- // larger type. Then bit-cast to unsigned .
361+ // Grow `zone` to fit a type of at least 32 bits, by
362+ // sign-extending it (the first bit is always 1, so are all
363+ // the preceding bits of the larger type) .
371364 // For types that already have the right size, all the
372365 // casting is a no-op.
373366 let zone = self . zone as $signed as $i_large as $u_large;
@@ -390,8 +383,7 @@ macro_rules! uniform_int_impl {
390383 {
391384 assert!( low < high,
392385 "Uniform::sample_single called with low >= high" ) ;
393- let range = ( high as $u_large)
394- . wrapping_sub( low as $u_large) ;
386+ let range = high. wrapping_sub( low) as $unsigned as $u_large;
395387 let zone =
396388 if :: core:: $unsigned:: MAX <= :: core:: u16 :: MAX as $unsigned {
397389 // Using a modulus is faster than the approximation for
0 commit comments