diff --git a/Lib/random.py b/Lib/random.py
index 1e0dcc87ed..e3dd48aa11 100644
--- a/Lib/random.py
+++ b/Lib/random.py
@@ -300,9 +300,16 @@ class Random(_random.Random):
x[i], x[j] = x[j], x[i]
else:
_int = int
+ _min = min
for i in reversed(range(1, len(x))):
- # pick an element in x[:i+1] with which to exchange x[i]
- j = _int(random() * (i+1))
+ # Pick an element in x[:i+1] with which to exchange x[i].
+ #
+ # The min() clamp was added for Issue #24567 to handle
+ # a rare and platform dependent situation where j could
+ # rounded to an invalid index. Periodically, we should
+ # assess whether this clamp is still necessary since it
+ # obscures and slows down the code.
+ j = _min(i, _int(random() * (i+1)))
x[i], x[j] = x[j], x[i]
def sample(self, population, k):
@@ -373,9 +380,16 @@ class Random(_random.Random):
random = self.random
if cum_weights is None:
if weights is None:
+ # The min() clamp was added for Issue #24567 to handle
+ # a rare and platform dependent situation where j could
+ # rounded to an invalid index. Periodically, we should
+ # assess whether this clamp is still necessary since it
+ # obscures and slows down the code.
_int = int
+ _min = min
total = len(population)
- return [population[_int(random() * total)] for i in range(k)]
+ return [population[_min(_int(random() * total), total)]
+ for i in range(k)]
cum_weights = list(_itertools.accumulate(weights))
elif weights is not None:
raise TypeError('Cannot specify both weights and cumulative weights')
@@ -383,7 +397,14 @@ class Random(_random.Random):
raise ValueError('The number of weights does not match the population')
bisect = _bisect.bisect
total = cum_weights[-1]
- return [population[bisect(cum_weights, random() * total)] for i in range(k)]
+ hi = len(population) - 1
+ # Clamping the bisect upper limit to *hi* was added for Issue
+ # #24567 to handle a rare and platform dependent situation where
+ # random()*total could slightly exceed the value of total.
+ # Periodically, we should assess whether this clamp is still
+ # necessary since it obscures and slows down the code.
+ return [population[bisect(cum_weights, random() * total, 0, hi)]
+ for i in range(k)]
## -------------------- real-valued distributions -------------------