Index: Lib/random.py =================================================================== --- Lib/random.py (revision 81980) +++ Lib/random.py (working copy) @@ -168,9 +168,12 @@ raise ValueError("non-integer arg 1 for randrange()") if stop is default: if istart > 0: - if istart >= maxwidth: + if istart >= 2**32: return self._randbelow(istart) - return int(self.random() * istart) + try: + return self._smallrandbelow(istart) + except AttributeError: + return int(self.random() * istart) raise ValueError("empty range for randrange()") # stop argument supplied. Index: Modules/_randommodule.c =================================================================== --- Modules/_randommodule.c (revision 81980) +++ Modules/_randommodule.c (working copy) @@ -369,7 +369,36 @@ return Py_None; } +/* Generate an integer uniformly distributed in the range [0, n), + for n in the range 0 < n < 2**32. */ + static PyObject * +random__smallrandbelow(RandomObject *self, PyObject *obj_n) +{ + unsigned long n, r, rmax; + + n = PyLong_AsUnsignedLong(obj_n); + if (n == (unsigned long)-1 && PyErr_Occurred()) + return NULL; + if (n == 0UL || n > 0xFFFFFFFFUL) { + PyErr_SetString(PyExc_OverflowError, + "Argument n to _smallrandbelow should " + "satisfy 0 < n < 2**32."); + return NULL; + } + + /* Generate an integer r, uniformly distributed in the range [0, rmax + 1), + where rmax + 1 is the largest multiple of n not exceeding 2**32. Then + r % n is uniformly distributed in the range [0, n). + */ + rmax = 0xFFFFFFFFUL - (0xFFFFFFFFUL - (n - 1UL)) % n; + r = genrand_int32(self); + while (r > rmax) + r = genrand_int32(self); + return PyLong_FromUnsignedLong(r % n); +} + +static PyObject * random_getrandbits(RandomObject *self, PyObject *args) { int k, i, bytes; @@ -443,6 +472,9 @@ {"getrandbits", (PyCFunction)random_getrandbits, METH_VARARGS, PyDoc_STR("getrandbits(k) -> x. Generates a long int with " "k random bits.")}, + {"_smallrandbelow", (PyCFunction)random__smallrandbelow, METH_O, + PyDoc_STR("smallrandbelow(n) -> integer. Generates an integer " + "in the range [0, n). Requires 0 < n < 2**32.")}, {NULL, NULL} /* sentinel */ };