diff --git a/Lib/random.py b/Lib/random.py --- a/Lib/random.py +++ b/Lib/random.py @@ -189,7 +189,10 @@ if istart > 0: if istart >= _maxwidth: return self._randbelow(istart) - return _int(self.random() * istart) + result = _int(self.random() * istart) + if result == istart: + result = istart - 1 + return result raise ValueError, "empty range for randrange()" # stop argument supplied. @@ -213,7 +216,10 @@ if width >= _maxwidth: return _int(istart + self._randbelow(width)) - return _int(istart + _int(self.random()*width)) + offset = _int(self.random() * width) + if offset == width: + offset = width - 1 + return _int(istart + offset) if step == 1: raise ValueError, "empty range for randrange() (%d,%d, %d)" % (istart, istop, width) @@ -233,7 +239,11 @@ if n >= _maxwidth: return istart + istep*self._randbelow(n) - return istart + istep*_int(self.random() * n) + + i = _int(self.random() * n) + if i == n: + i = n - 1 + return istart + istep * i def randint(self, a, b): """Return random integer in range [a, b], including both end points. @@ -272,7 +282,11 @@ def choice(self, seq): """Choose a random element from a non-empty sequence.""" - return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty + n = len(seq) + i = int(self.random() * n) + if i == n and n > 0: + i = n - 1 + return seq[i] # raises IndexError if seq is empty def shuffle(self, x, random=None): """x, random=random.random -> shuffle list x in place; return None. @@ -288,7 +302,8 @@ for i in reversed(xrange(1, len(x))): # pick an element in x[:i+1] with which to exchange x[i] j = _int(random() * (i+1)) - x[i], x[j] = x[j], x[i] + if j < i: + x[i], x[j] = x[j], x[i] def sample(self, population, k): """Chooses k unique random elements from a population sequence. @@ -332,17 +347,24 @@ # mapping type so the other algorithm wouldn't work. pool = list(population) for i in xrange(k): # invariant: non-selected at [0,n-i) - j = _int(random() * (n-i)) + limit = n - i + j = _int(random() * limit) + if j == limit: + j = limit - 1 result[i] = pool[j] - pool[j] = pool[n-i-1] # move non-selected item into vacancy + pool[j] = pool[limit-1] # move non-selected item into vacancy else: try: selected = set() selected_add = selected.add for i in xrange(k): j = _int(random() * n) + if j == n: + j = n - 1 while j in selected: j = _int(random() * n) + if j == n: + j = n - 1 selected_add(j) result[i] = population[j] except (TypeError, KeyError): # handle (at least) sets