diff options
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | README.md | 13 | ||||
| -rw-r--r-- | SyncRNG.R | 4 | ||||
| -rw-r--r-- | syncrng.c | 104 |
4 files changed, 63 insertions, 61 deletions
@@ -14,5 +14,4 @@ R: clean: rm -rf build - rm -f *.so *.o - rm *.pyc + rm -f *.so *.o *.pyc @@ -52,18 +52,11 @@ You'll notice that the random numbers are indeed the same. Notes ----- -Since R is not capable of reliably handling integers larger than `2^32 - 1`, -the random numbers are internally capped at this value (using a bitwise and -with `0x7FFFFFF`), this influences the quality of the random numbers. The -random numbers are no longer uniformly distributed on `[0, 2^32 -1]`. For the -intended use of SyncRNG this is not a problem, but it is a compromise worth -considering when using SyncRNG. SyncRNG should definitely not be used for any -cryptographic purposes. +The random numbers are uniformly distributed on `[0, 2^32 - 1]`. TODO ---- -Future versions may include a random number generator that does not need -capping, and is uniform. It may also provide easier system-wide installation -through an R package and a Python module. +It may be easier to provide system-wide installation through an R package and +a Python module. @@ -11,13 +11,13 @@ SyncRNG <- setRefClass('SyncRNG', initialize=function(..., seed=0) { seed <<- seed tmp <- .Call('R_syncrng_seed', - as.integer(seed)) + as.numeric(seed)) state <<- tmp[1:4] callSuper(...) }, randi=function() { tmp <- .Call('R_syncrng_rand', - as.integer(state)) + as.numeric(state)) state <<- tmp[1:4] return(tmp[5]) }, @@ -15,9 +15,9 @@ * * @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. + * an additional step, the resulting random number is capped to 0xFFFFFFFF + * using a bitwise and. This is done to yield the range [0, 2^32-1]. On + * return, the state variables are updated. * * [1]: @article{l1996maximally, * title={Maximally equidistributed combined Tausworthe generators}, @@ -34,7 +34,7 @@ * * @return a generated random number */ -int lfsr113(int **state) +unsigned long lfsr113(unsigned long **state) { unsigned long z1, z2, z3, z4, b; @@ -57,11 +57,12 @@ int lfsr113(int **state) b = (z1 ^ z2 ^ z3 ^ z4); - (*state)[0] = z1 & 0x7FFFFFFF; - (*state)[1] = z2 & 0x7FFFFFFF; - (*state)[2] = z3 & 0x7FFFFFFF; - (*state)[3] = z4 & 0x7FFFFFFF; - b = b & 0x7FFFFFFF; + (*state)[0] = z1; + (*state)[1] = z2; + (*state)[2] = z3; + (*state)[3] = z4; + + b = b & 0xFFFFFFFF; return(b); } @@ -72,32 +73,36 @@ int lfsr113(int **state) * @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. + * than 1, 7, 15, and 127 respectively. * * @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) +void lfsr113_seed(unsigned long seed, unsigned long **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; + z1 = (z1 * (seed + 1)); + z2 = (z2 * (seed + 1)); + z3 = (z3 * (seed + 1)); + z4 = (z4 * (seed + 1)); + + z1 = (z1 > 1) ? z1 : z1 + 1; + z2 = (z2 > 7) ? z2 : z2 + 7; + z3 = (z3 > 15) ? z3 : z3 + 15; + z4 = (z4 > 127) ? z4 : z4 + 127; if (*state == NULL) { - (*state) = malloc(sizeof(int)*4); + (*state) = malloc(sizeof(unsigned long)*4); } - (*state)[0] = (int) z1; - (*state)[1] = (int) z2; - (*state)[2] = (int) z3; - (*state)[3] = (int) z4; + (*state)[0] = z1; + (*state)[1] = z2; + (*state)[2] = z3; + (*state)[3] = z4; } #ifdef TARGETPYTHON @@ -109,13 +114,14 @@ void lfsr113_seed(unsigned long seed, int **state) static PyObject *syncrng_seed(PyObject *self, PyObject *args) { - int seed, *state = NULL; + unsigned long seed, *state = NULL; - if (!PyArg_ParseTuple(args, "i", &seed)) + if (!PyArg_ParseTuple(args, "k", &seed)) return NULL; lfsr113_seed(seed, &state); - PyObject *pystate = Py_BuildValue("[i, i, i, i]", + + PyObject *pystate = Py_BuildValue("[k, k, k, k]", state[0], state[1], state[2], state[3]); free(state); return pystate; @@ -123,7 +129,7 @@ static PyObject *syncrng_seed(PyObject *self, PyObject *args) static PyObject *syncrng_rand(PyObject *self, PyObject *args) { - int i, value, numints, *localstate; + unsigned long i, value, numints, *localstate; PyObject *listObj; PyObject *intObj; @@ -132,18 +138,18 @@ static PyObject *syncrng_rand(PyObject *self, PyObject *args) return NULL; // we're just assuming you would never pass more than 4 values - localstate = malloc(sizeof(int)*5); + localstate = malloc(sizeof(unsigned long)*5); numints = PyList_Size(listObj); for (i=0; i<numints; i++) { intObj = PyList_GetItem(listObj, i); - value = (int) PyLong_AsLong(intObj); + value = (unsigned long) PyLong_AsLong(intObj); localstate[i] = value; } - int rand = lfsr113(&localstate); + unsigned long rand = lfsr113(&localstate); localstate[4] = rand; - PyObject *pystate = Py_BuildValue("[i, i, i, i, i]", + PyObject *pystate = Py_BuildValue("[k, k, k, k, k]", localstate[0], localstate[1], localstate[2], localstate[3], rand); free(localstate); @@ -175,18 +181,20 @@ PyMODINIT_FUNC initsyncrng(void) */ 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); + int i; + double *pseed = REAL(seed), + *pstate = NULL; + unsigned long useed = (unsigned long) *pseed; + unsigned long *state = NULL; - lfsr113_seed(*pseed, &state); + lfsr113_seed(useed, &state); + SEXP Rstate = PROTECT(allocVector(REALSXP, 5)); + pstate = REAL(Rstate); for (i=0; i<4; i++) { - pstate[i] = state[i]; + pstate[i] = (double) state[i]; } - pstate[4] = -1; + pstate[4] = -1.0; free(state); UNPROTECT(1); @@ -195,20 +203,22 @@ SEXP R_syncrng_seed(SEXP seed) SEXP R_syncrng_rand(SEXP state) { - int *localstate = malloc(sizeof(int)*4); - int *pstate = INTEGER(state); + unsigned long *localstate = malloc(sizeof(unsigned long)*4); + double *pstate = REAL(state); int i; - for (i=0; i<4; i++) - localstate[i] = pstate[i]; + for (i=0; i<4; i++) { + localstate[i] = (unsigned long) pstate[i]; + } - int rand = lfsr113(&localstate); + unsigned long rand = lfsr113(&localstate); - SEXP Rstate = PROTECT(allocVector(INTSXP, 5)); - pstate = INTEGER(Rstate); + SEXP Rstate = PROTECT(allocVector(REALSXP, 5)); + pstate = REAL(Rstate); - for (i=0; i<4; i++) - pstate[i] = localstate[i]; - pstate[4] = rand; + for (i=0; i<4; i++) { + pstate[i] = (double) localstate[i]; + } + pstate[4] = (double) rand; UNPROTECT(1); free(localstate); |
