Skip to content

Commit acda5ea

Browse files
bpo-24567: Random subnormal.diff (GH-7954) (GH-7956)
Handle subnormal weights for choices() (cherry picked from commit ddf7171) Co-authored-by: Raymond Hettinger <[email protected]>
1 parent 6abf8c1 commit acda5ea

File tree

3 files changed

+13
-1
lines changed

3 files changed

+13
-1
lines changed

‎Lib/random.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,9 @@ def choices(self, population, weights=None, *, cum_weights=None, k=1):
360360
raise ValueError('The number of weights does not match the population')
361361
bisect = _bisect.bisect
362362
total = cum_weights[-1]
363-
return [population[bisect(cum_weights, random() * total)] for i in range(k)]
363+
hi = len(cum_weights) - 1
364+
return [population[bisect(cum_weights, random() * total, 0, hi)]
365+
for i in range(k)]
364366

365367
## -------------------- real-valued distributions -------------------
366368

‎Lib/test/test_random.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,14 @@ def test_choices(self):
220220
with self.assertRaises(IndexError):
221221
choices([], cum_weights=[], k=5)
222222

223+
def test_choices_subnormal(self):
224+
# Subnormal weights would occassionally trigger an IndexError
225+
# in choices() when the value returned by random() was large
226+
# enough to make `random() * total` round up to the total.
227+
# See https://bugs.python.org/msg275594 for more detail.
228+
choices = self.gen.choices
229+
choices(population=[1, 2], weights=[1e-323, 1e-323], k=5000)
230+
223231
def test_gauss(self):
224232
# Ensure that the seed() method initializes all the hidden state. In
225233
# particular, through 2.2.1 it failed to reset a piece of state used
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve random.choices() to handle subnormal input weights that could
2+
occasionally trigger an IndexError.

0 commit comments

Comments
 (0)