bpo-24567: Random subnormal.diff (GH-7954) (GH-7956) · python/cpython@acda5ea (original) (raw)

3 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -360,7 +360,9 @@ def choices(self, population, weights=None, *, cum_weights=None, k=1):
360 360 raise ValueError('The number of weights does not match the population')
361 361 bisect = _bisect.bisect
362 362 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)]
364 366
365 367 ## -------------------- real-valued distributions -------------------
366 368
Original file line number Diff line number Diff line change
@@ -220,6 +220,14 @@ def test_choices(self):
220 220 with self.assertRaises(IndexError):
221 221 choices([], cum_weights=[], k=5)
222 222
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 +
223 231 def test_gauss(self):
224 232 # Ensure that the seed() method initializes all the hidden state. In
225 233 # particular, through 2.2.1 it failed to reset a piece of state used
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 +Improve random.choices() to handle subnormal input weights that could
2 +occasionally trigger an IndexError.