From 2f726e9093381572b21edbfc42659ea89fbdf686 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 5 Oct 2003 09:09:15 +0000 Subject: SF bug #812202: randint is always even * Added C coded getrandbits(k) method that runs in linear time. * Call the new method from randrange() for ranges >= 2**53. * Adds a warning for generators not defining getrandbits() whenever they have a call to randrange() with too large of a population. --- Modules/_randommodule.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'Modules/_randommodule.c') diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 4a87a8e8e9..1189036e9d 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -434,6 +434,47 @@ random_jumpahead(RandomObject *self, PyObject *n) return Py_None; } +static PyObject * +random_getrandbits(RandomObject *self, PyObject *args) +{ + int k, i, bytes; + unsigned long r; + unsigned char *bytearray; + PyObject *result; + + if (!PyArg_ParseTuple(args, "i:getrandbits", &k)) + return NULL; + + if (k <= 0) { + PyErr_SetString(PyExc_ValueError, + "number of bits must be greater than zero"); + return NULL; + } + + bytes = ((k - 1) / 32 + 1) * 4; + bytearray = (unsigned char *)PyMem_Malloc(bytes); + if (bytearray == NULL) { + PyErr_NoMemory(); + return NULL; + } + + /* Fill-out whole words, byte-by-byte to avoid endianness issues */ + for (i=0 ; i>= (32 - k); + bytearray[i+0] = (unsigned char)r; + bytearray[i+1] = (unsigned char)(r >> 8); + bytearray[i+2] = (unsigned char)(r >> 16); + bytearray[i+3] = (unsigned char)(r >> 24); + } + + /* little endian order to match bytearray assignment order */ + result = _PyLong_FromByteArray(bytearray, bytes, 1, 0); + PyMem_Free(bytearray); + return result; +} + static PyObject * random_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -464,6 +505,9 @@ static PyMethodDef random_methods[] = { {"jumpahead", (PyCFunction)random_jumpahead, METH_O, PyDoc_STR("jumpahead(int) -> None. Create new state from " "existing state and integer.")}, + {"getrandbits", (PyCFunction)random_getrandbits, METH_VARARGS, + PyDoc_STR("getrandbits(k) -> x. Generates a long int with " + "k random bits.")}, {NULL, NULL} /* sentinel */ }; -- cgit v1.2.1