mirror of
https://github.com/python/cpython.git
synced 2025-12-09 18:48:05 +00:00
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.
This commit is contained in:
parent
5c68ef04b7
commit
2f726e9093
5 changed files with 196 additions and 10 deletions
|
|
@ -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<bytes ; i+=4, k-=32) {
|
||||
r = genrand_int32(self);
|
||||
if (k < 32)
|
||||
r >>= (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 */
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue