diff options
| author | Gertjan van den Burg <gertjanvandenburg@gmail.com> | 2015-07-30 16:07:50 +0200 |
|---|---|---|
| committer | Gertjan van den Burg <gertjanvandenburg@gmail.com> | 2015-07-30 16:07:50 +0200 |
| commit | dec32e1516a05db805ff75a9e016e8bea04d1d8e (patch) | |
| tree | 1087efc189d5ca533ac01fec6746347212d66202 /syncrng.c | |
| parent | added readme (diff) | |
| download | SyncRNG-dec32e1516a05db805ff75a9e016e8bea04d1d8e.tar.gz SyncRNG-dec32e1516a05db805ff75a9e016e8bea04d1d8e.zip | |
name change to SyncRNG and documentation in the .c file
Diffstat (limited to 'syncrng.c')
| -rw-r--r-- | syncrng.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/syncrng.c b/syncrng.c new file mode 100644 index 0000000..deb9439 --- /dev/null +++ b/syncrng.c @@ -0,0 +1,223 @@ +#ifdef TARGETPYTHON +#include "Python.h" +#endif + +#ifndef TARGETPYTHON +#define STRICT_R_HEADERS +#include <stdio.h> +#include <stdlib.h> +#include <R.h> +#include <Rinternals.h> +#endif + +/** + * @brief Generate a single random number using the capped Tausworthe RNG + * + * @details + * This generates random numbers according to the process described in [1]. As + * an additional step, the state variables are capped to 0x7FFFFFFF using a + * bitwise and. This is to overcome limitations of R. On return, the state + * variables are updated. + * + * [1]: @article{l1996maximally, + * title={Maximally equidistributed combined Tausworthe generators}, + * author={L’ecuyer, Pierre}, + * journal={Mathematics of Computation of the American Mathematical + * Society}, + * volume={65}, + * number={213}, + * pages={203--213}, + * year={1996} + * } + * + * @param[in,out] state pointer to current state array + * + * @return a generated random number + */ +int lfsr113(int **state) +{ + unsigned long z1, z2, z3, z4, b; + + z1 = (*state)[0]; + z2 = (*state)[1]; + z3 = (*state)[2]; + z4 = (*state)[3]; + + b = (((z1 << 6) ^ z1) >> 13); + z1 = (((z1 & 4294967294) << 18) ^ b); + + b = (((z2 << 2) ^ z2) >> 27); + z2 = (((z2 & 4294967288) << 2) ^ b); + + b = (((z3 << 13) ^ z3) >> 21); + z3 = (((z3 & 4294967280) << 7) ^ b); + + b = (((z4 << 3) ^ z4) >> 12); + z4 = (((z4 & 4294967168) << 13) ^ b); + + b = (z1 ^ z2 ^ z3 ^ z4); + + (*state)[0] = z1 & 0x7FFFFFFF; + (*state)[1] = z2 & 0x7FFFFFFF; + (*state)[2] = z3 & 0x7FFFFFFF; + (*state)[3] = z4 & 0x7FFFFFFF; + b = b & 0x7FFFFFFF; + + return(b); +} + +/** + * @brief Seed the Tausworthe RNG using a seed value + * + * @details + * This function seeds the state array using a supplied seed value. As noted + * in [1] (see lfsr113()), the values of z1, z2, z3, and z4 should be larger + * than 1, 7, 15, and 127 respectively. Here too the state variables are + * capped at 0x7FFFFFF. + * + * @param[in] seed user supplied seed value for the RNG + * @param[out] state state of the RNG + */ +void lfsr113_seed(unsigned long seed, int **state) +{ + unsigned long z1 = 2, + z2 = 8, + z3 = 16, + z4 = 128; + + z1 = (z1 * (seed + 1)) & 0x7FFFFFFF; + z2 = (z2 * (seed + 1)) & 0x7FFFFFFF; + z3 = (z3 * (seed + 1)) & 0x7FFFFFFF; + z4 = (z4 * (seed + 1)) & 0x7FFFFFFF; + + if (*state == NULL) { + (*state) = malloc(sizeof(int)*4); + } + + (*state)[0] = (int) z1; + (*state)[1] = (int) z2; + (*state)[2] = (int) z3; + (*state)[3] = (int) z4; +} + +#ifdef TARGETPYTHON +/* + * + * Start of Python code + * + */ + +static PyObject *syncrng_seed(PyObject *self, PyObject *args) +{ + int seed, *state = NULL; + + if (!PyArg_ParseTuple(args, "i", &seed)) + return NULL; + + lfsr113_seed(seed, &state); + PyObject *pystate = Py_BuildValue("[i, i, i, i]", + state[0], state[1], state[2], state[3]); + free(state); + return pystate; +} + +static PyObject *syncrng_rand(PyObject *self, PyObject *args) +{ + int i, value, numints, *localstate; + + PyObject *listObj; + PyObject *intObj; + + if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &listObj)) + return NULL; + + // we're just assuming you would never pass more than 4 values + localstate = malloc(sizeof(int)*5); + numints = PyList_Size(listObj); + for (i=0; i<numints; i++) { + intObj = PyList_GetItem(listObj, i); + value = (int) PyLong_AsLong(intObj); + localstate[i] = value; + } + + int rand = lfsr113(&localstate); + localstate[4] = rand; + + PyObject *pystate = Py_BuildValue("[i, i, i, i, i]", + localstate[0], localstate[1], localstate[2], + localstate[3], rand); + free(localstate); + return pystate; +} + +static PyMethodDef SyncRNGMethods[] = { + {"seed", syncrng_seed, METH_VARARGS, + "Seed the RNG."}, + {"rand", syncrng_rand, METH_VARARGS, + "Generate a single random integer using SyncRNG."}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initsyncrng(void) +{ + PyObject *m = Py_InitModule3("syncrng", SyncRNGMethods, + "Python interface to SyncRNG"); + if (m == NULL) + return; +} +#endif + +#ifndef TARGETPYTHON +/* + * + * Start of R code + * + */ +SEXP R_syncrng_seed(SEXP seed) +{ + int i, *pstate = NULL, *state = NULL; + int *pseed = INTEGER(seed); + + SEXP Rstate = PROTECT(allocVector(INTSXP, 5)); + pstate = INTEGER(Rstate); + + lfsr113_seed(*pseed, &state); + + for (i=0; i<4; i++) { + pstate[i] = state[i]; + } + pstate[4] = -1; + free(state); + + UNPROTECT(1); + return Rstate; +} + +SEXP R_syncrng_rand(SEXP state) +{ + int *localstate = malloc(sizeof(int)*4); + int *pstate = INTEGER(state); + int i; + for (i=0; i<4; i++) + localstate[i] = pstate[i]; + + int rand = lfsr113(&localstate); + + SEXP Rstate = PROTECT(allocVector(INTSXP, 5)); + pstate = INTEGER(Rstate); + + for (i=0; i<4; i++) + pstate[i] = localstate[i]; + pstate[4] = rand; + UNPROTECT(1); + + free(localstate); + + return Rstate; +} +/* + * + * End of R code + * + */ +#endif |
