bpo-24567: Random subnormal.diff (#7954) · python/cpython@ddf7171 (original) (raw)
3 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -383,7 +383,9 @@ def choices(self, population, weights=None, *, cum_weights=None, k=1): | ||
383 | 383 | raise ValueError('The number of weights does not match the population') |
384 | 384 | bisect = _bisect.bisect |
385 | 385 | total = cum_weights[-1] |
386 | -return [population[bisect(cum_weights, random() * total)] for i in range(k)] | |
386 | +hi = len(cum_weights) - 1 | |
387 | +return [population[bisect(cum_weights, random() * total, 0, hi)] | |
388 | +for i in range(k)] | |
387 | 389 | |
388 | 390 | ## -------------------- real-valued distributions ------------------- |
389 | 391 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -227,6 +227,14 @@ def test_choices(self): | ||
227 | 227 | with self.assertRaises(IndexError): |
228 | 228 | choices([], cum_weights=[], k=5) |
229 | 229 | |
230 | +def test_choices_subnormal(self): | |
231 | +# Subnormal weights would occassionally trigger an IndexError | |
232 | +# in choices() when the value returned by random() was large | |
233 | +# enough to make `random() * total` round up to the total. | |
234 | +# See https://bugs.python.org/msg275594 for more detail. | |
235 | +choices = self.gen.choices | |
236 | +choices(population=[1, 2], weights=[1e-323, 1e-323], k=5000) | |
237 | + | |
230 | 238 | def test_gauss(self): |
231 | 239 | # Ensure that the seed() method initializes all the hidden state. In |
232 | 240 | # 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. |