@@ -288,17 +288,12 @@ impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {
288
288
/// `ints_to_reject = (unsigned_max - range + 1) % range;`
289
289
///
290
290
/// 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
292
292
/// 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.
302
297
///
303
298
/// An alternative to using a modulus is widening multiply: After a widening
304
299
/// multiply by `range`, the result is in the high word. Then comparing the low
@@ -341,11 +336,9 @@ macro_rules! uniform_int_impl {
341
336
fn new_inclusive( low: Self :: X , high: Self :: X ) -> Self {
342
337
assert!( low <= high,
343
338
"Uniform::new_inclusive called with `low > high`" ) ;
344
- let unsigned_max: $u_large = :: core:: $u_large :: MAX ;
339
+ let unsigned_max = :: core:: $unsigned :: MAX ;
345
340
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;
349
342
let ints_to_reject =
350
343
if range > 0 {
351
344
( unsigned_max - range + 1 ) % range
@@ -365,9 +358,9 @@ macro_rules! uniform_int_impl {
365
358
fn sample<R : Rng + ?Sized >( & self , rng: & mut R ) -> Self :: X {
366
359
let range = self . range as $unsigned as $u_large;
367
360
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) .
371
364
// For types that already have the right size, all the
372
365
// casting is a no-op.
373
366
let zone = self . zone as $signed as $i_large as $u_large;
@@ -390,8 +383,7 @@ macro_rules! uniform_int_impl {
390
383
{
391
384
assert!( low < high,
392
385
"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;
395
387
let zone =
396
388
if :: core:: $unsigned:: MAX <= :: core:: u16 :: MAX as $unsigned {
397
389
// Using a modulus is faster than the approximation for
0 commit comments