@@ -296,15 +296,15 @@ pub trait IteratorRandom: Iterator + Sized {
296
296
/// depends on size hints. In particular, `Iterator` combinators that don't
297
297
/// change the values yielded but change the size hints may result in
298
298
/// `choose` returning different elements.
299
- ///
300
- /// For slices, prefer [`SliceRandom::choose`] which guarantees `O(1)`
301
- /// performance.
302
299
fn choose < R > ( mut self , rng : & mut R ) -> Option < Self :: Item >
303
300
where R : Rng + ?Sized {
304
301
let ( mut lower, mut upper) = self . size_hint ( ) ;
305
302
let mut consumed = 0 ;
306
303
let mut result = None ;
307
304
305
+ // Handling for this condition outside the loop allows the optimizer to eliminate the loop
306
+ // when the Iterator is an ExactSizeIterator. This has a large performance impact on e.g.
307
+ // seq_iter_choose_from_1000.
308
308
if upper == Some ( lower) {
309
309
return if lower == 0 {
310
310
None
@@ -336,8 +336,7 @@ pub trait IteratorRandom: Iterator + Sized {
336
336
return result;
337
337
}
338
338
consumed += 1 ;
339
- let denom = consumed as f64 ; // accurate to 2^53 elements
340
- if rng. gen_bool ( 1.0 / denom) {
339
+ if gen_index ( rng, consumed) == 0 {
341
340
result = elem;
342
341
}
343
342
}
@@ -963,7 +962,7 @@ mod test {
963
962
964
963
assert_eq ! ( choose( [ ] . iter( ) . cloned( ) ) , None ) ;
965
964
assert_eq ! ( choose( 0 ..100 ) , Some ( 33 ) ) ;
966
- assert_eq ! ( choose( UnhintedIterator { iter: 0 ..100 } ) , Some ( 76 ) ) ;
965
+ assert_eq ! ( choose( UnhintedIterator { iter: 0 ..100 } ) , Some ( 40 ) ) ;
967
966
assert_eq ! (
968
967
choose( ChunkHintedIterator {
969
968
iter: 0 ..100 ,
0 commit comments