aboutsummaryrefslogtreecommitdiff
path: root/R
diff options
context:
space:
mode:
authorGertjan van den Burg <gertjanvandenburg@gmail.com>2021-01-14 17:30:12 +0000
committerGertjan van den Burg <gertjanvandenburg@gmail.com>2021-01-14 17:30:12 +0000
commit201e19975461c6fb04d4487346e2a0b68d2359dc (patch)
tree0cf71b412b17670bf7e2c12b8e26c1dada051b5a /R
parentMerge branch 'python' (diff)
downloadSyncRNG-201e19975461c6fb04d4487346e2a0b68d2359dc.tar.gz
SyncRNG-201e19975461c6fb04d4487346e2a0b68d2359dc.zip
Rename directories, remove extra test dir
Diffstat (limited to 'R')
-rw-r--r--R/DESCRIPTION15
-rw-r--r--R/NAMESPACE7
-rw-r--r--R/NEWS.md4
-rw-r--r--R/R/SyncRNG.R76
-rw-r--r--R/R/syncrng-package.R50
-rw-r--r--R/cran-comments.md17
-rw-r--r--R/man/SyncRNG-class.Rd39
-rw-r--r--R/man/syncrng-package.Rd52
-rw-r--r--R/src/_syncrng.c381
-rw-r--r--R/src/syncrng.c407
-rw-r--r--R/tests/testthat.R4
-rw-r--r--R/tests/testthat/first_1000_seed_0.txt1000
-rw-r--r--R/tests/testthat/tests.R63
13 files changed, 2115 insertions, 0 deletions
diff --git a/R/DESCRIPTION b/R/DESCRIPTION
new file mode 100644
index 0000000..141743a
--- /dev/null
+++ b/R/DESCRIPTION
@@ -0,0 +1,15 @@
+Package: SyncRNG
+Version: 1.3.0
+Date: 2017-12-15
+Title: A Synchronized Tausworthe RNG for R and Python
+Author: Gertjan van den Burg <gertjanvandenburg@gmail.com>
+Maintainer: Gertjan van den Burg <gertjanvandenburg@gmail.com>
+Depends:
+ R (>= 3.0.0)
+Description: Random number generation designed for cross-language usage.
+License: GPL-2
+Imports:
+ methods
+Suggests:
+ testthat
+RoxygenNote: 7.1.1
diff --git a/R/NAMESPACE b/R/NAMESPACE
new file mode 100644
index 0000000..052e9e8
--- /dev/null
+++ b/R/NAMESPACE
@@ -0,0 +1,7 @@
+# Generated by roxygen2: do not edit by hand
+
+export(SyncRNG)
+exportClasses(SyncRNG)
+import(methods)
+importFrom(methods,new)
+useDynLib(SyncRNG, .registration = TRUE)
diff --git a/R/NEWS.md b/R/NEWS.md
new file mode 100644
index 0000000..8b038d8
--- /dev/null
+++ b/R/NEWS.md
@@ -0,0 +1,4 @@
+# SyncRNG 1.3.0
+
+* Allows using SyncRNG as a user-supplied random number generator in R. This
+ enables using the functions ``runif`` and ``rnorm``.
diff --git a/R/R/SyncRNG.R b/R/R/SyncRNG.R
new file mode 100644
index 0000000..e7176b4
--- /dev/null
+++ b/R/R/SyncRNG.R
@@ -0,0 +1,76 @@
+library(methods)
+
+#' A Reference Class for SyncRNG
+#'
+#' See \link{syncrng-package} for package documentation.
+#'
+#' @field seed The seed for the random number generator
+#' @field state The current state of the RNG, should not be modified by the
+#' user
+#'
+#' @useDynLib SyncRNG, .registration = TRUE
+#' @export SyncRNG
+#' @exportClass SyncRNG
+#' @importFrom methods new
+#'
+#' @examples
+#' s <- SyncRNG(seed=123456)
+#' for (i in 1:10)
+#' cat(s$randi(), '\n')
+#'
+SyncRNG <- setRefClass('SyncRNG',
+ fields=list(
+ seed='numeric',
+ state='numeric'
+ ),
+ methods=list(
+ initialize=function(..., seed=0) {
+ "Initialize the RNG using the C function R_syncrng_seed"
+ seed <<- seed
+ tmp <- .Call('R_syncrng_seed',
+ as.numeric(seed))
+ state <<- tmp[1:4]
+ callSuper(...)
+ },
+ randi=function() {
+ "Generate a single random 32-bit integer"
+ tmp <- .Call('R_syncrng_rand',
+ as.numeric(state))
+ state <<- tmp[1:4]
+ return(tmp[5])
+ },
+ rand=function() {
+ "Generate a single random float in the range [0, 1)"
+ r <- randi()
+ return (r * 2.3283064365387e-10)
+ },
+ randbelow=function(n) {
+ "Generate a random integer below a given number"
+ maxsize <- 2^32
+ if (n >= maxsize) {
+ warning(paste("Underlying random generator ",
+ "does not supply\n enough bits ",
+ "to choose from a population ",
+ "range this large.\n"))
+ return(round(rand() * n))
+ }
+ rem <- maxsize %% n
+ limit <- (maxsize - rem) / maxsize
+ r <- rand()
+ while (r >= limit)
+ r <- rand()
+ return(round(r*maxsize) %% n)
+ },
+ shuffle=function(x) {
+ "Randomly shuffle a provided array of values"
+ y <- x
+ for (i in rev(1:(length(y)-1))) {
+ j <- randbelow(i+1)
+ tmp <- y[i+1]
+ y[i+1] <- y[j+1]
+ y[j+1] <- tmp
+ }
+ return(y)
+ }
+ )
+ )
diff --git a/R/R/syncrng-package.R b/R/R/syncrng-package.R
new file mode 100644
index 0000000..949401d
--- /dev/null
+++ b/R/R/syncrng-package.R
@@ -0,0 +1,50 @@
+#' @title SyncRNG - Synchronized Random Numbers in R and Python
+#'
+#' @description
+#' The SyncRNG package provides a random number generator implemented in C and
+#' linked to both R and Python. This way, you can generate the same random
+#' number sequence in both languages by using the same seed.
+#'
+#' The package implements a Tausworthe LSFR RNG (more details at
+#' \url{https://gertjanvandenburg.com/blog/syncrng/}). This is a very fast
+#' pseudo-random number generator.
+#'
+#' @section Usage:
+#' There are two ways to use this package in R. It can be used as a reference
+#' class, where a SyncRNG object is used to keep the state of the generator and
+#' numbers are generated using the object methods. It can also be used as a
+#' user-defined random number generator using the strategy outlined in
+#' .Random.user. See the examples section below.
+#'
+#' @author
+#' Gerrit J.J. van den Burg\cr
+#' Maintainer: Gerrit J.J. van den Burg <gertjanvandenburg@gmail.com>
+#'
+#' @references
+#' URL: \url{https://github.com/GjjvdBurg/SyncRNG}
+#'
+#' @examples
+#' library(SyncRNG)
+#'
+#' # As user defined RNG:
+#'
+#' set.seed(0, 'user', 'user')
+#' runif(2)
+#' # [1] 3.666952e-04 6.257184e-05
+#' set.seed(0, 'user', 'user')
+#' rnorm(2)
+#' # [1] 0.01006027 0.42889422
+#'
+#' # As class:
+#'
+#' s <- SyncRNG(seed=0)
+#' s$rand()
+#' # [1] 0.0003666952
+#' s$rand()
+#' # [1] 6.257184e-05
+#'
+#' @name syncrng-package
+#' @docType package
+#' @import methods
+NULL
+#>NULL
diff --git a/R/cran-comments.md b/R/cran-comments.md
new file mode 100644
index 0000000..4f984f0
--- /dev/null
+++ b/R/cran-comments.md
@@ -0,0 +1,17 @@
+## Test environments
+* local Arch Linux install, R 3.4.3
+* win-builder (devel and release)
+
+## R CMD check results
+There were no ERRORs or WARNINGs.
+
+There was 1 NOTE:
+
+* checking CRAN incoming feasibility ... NOTE
+Maintainer: 'Gertjan van den Burg <gertjanvandenburg@gmail.com>'
+
+Possibly mis-spelled words in DESCRIPTION:
+ RNG (4:34)
+ Tausworthe (4:23)
+
+ RNG is a common abbreviation and Tausworthe is a name.
diff --git a/R/man/SyncRNG-class.Rd b/R/man/SyncRNG-class.Rd
new file mode 100644
index 0000000..92316da
--- /dev/null
+++ b/R/man/SyncRNG-class.Rd
@@ -0,0 +1,39 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/SyncRNG.R
+\docType{class}
+\name{SyncRNG-class}
+\alias{SyncRNG-class}
+\alias{SyncRNG}
+\title{A Reference Class for SyncRNG}
+\description{
+See \link{syncrng-package} for package documentation.
+}
+\section{Fields}{
+
+\describe{
+\item{\code{seed}}{The seed for the random number generator}
+
+\item{\code{state}}{The current state of the RNG, should not be modified by the
+user}
+}}
+
+\section{Methods}{
+
+\describe{
+\item{\code{initialize(..., seed = 0)}}{Initialize the RNG using the C function R_syncrng_seed}
+
+\item{\code{rand()}}{Generate a single random float in the range [0, 1)}
+
+\item{\code{randbelow(n)}}{Generate a random integer below a given number}
+
+\item{\code{randi()}}{Generate a single random 32-bit integer}
+
+\item{\code{shuffle(x)}}{Randomly shuffle a provided array of values}
+}}
+
+\examples{
+s <- SyncRNG(seed=123456)
+for (i in 1:10)
+ cat(s$randi(), '\n')
+
+}
diff --git a/R/man/syncrng-package.Rd b/R/man/syncrng-package.Rd
new file mode 100644
index 0000000..f8cfe02
--- /dev/null
+++ b/R/man/syncrng-package.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/syncrng-package.R
+\docType{package}
+\name{syncrng-package}
+\alias{syncrng-package}
+\title{SyncRNG - Synchronized Random Numbers in R and Python}
+\description{
+The SyncRNG package provides a random number generator implemented in C and
+linked to both R and Python. This way, you can generate the same random
+number sequence in both languages by using the same seed.
+
+The package implements a Tausworthe LSFR RNG (more details at
+\url{https://gertjanvandenburg.com/blog/syncrng/}). This is a very fast
+pseudo-random number generator.
+}
+\section{Usage}{
+
+There are two ways to use this package in R. It can be used as a reference
+class, where a SyncRNG object is used to keep the state of the generator and
+numbers are generated using the object methods. It can also be used as a
+user-defined random number generator using the strategy outlined in
+.Random.user. See the examples section below.
+}
+
+\examples{
+library(SyncRNG)
+
+# As user defined RNG:
+
+set.seed(0, 'user', 'user')
+runif(2)
+# [1] 3.666952e-04 6.257184e-05
+set.seed(0, 'user', 'user')
+rnorm(2)
+# [1] 0.01006027 0.42889422
+
+# As class:
+
+s <- SyncRNG(seed=0)
+s$rand()
+# [1] 0.0003666952
+s$rand()
+# [1] 6.257184e-05
+
+}
+\references{
+URL: \url{https://github.com/GjjvdBurg/SyncRNG}
+}
+\author{
+Gerrit J.J. van den Burg\cr
+Maintainer: Gerrit J.J. van den Burg <gertjanvandenburg@gmail.com>
+}
diff --git a/R/src/_syncrng.c b/R/src/_syncrng.c
new file mode 100644
index 0000000..bd1612a
--- /dev/null
+++ b/R/src/_syncrng.c
@@ -0,0 +1,381 @@
+#ifdef TARGETPYTHON
+#include "Python.h"
+#include <stdint.h>
+#endif
+
+#ifndef TARGETPYTHON
+#define STRICT_R_HEADERS
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <R.h>
+#include <Rinternals.h>
+#include <R_ext/Random.h>
+#include <R_ext/Rdynload.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 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},
+ * 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
+ */
+uint32_t lfsr113(uint64_t **state)
+{
+ uint64_t z1, z2, z3, z4;
+ uint64_t 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;
+ (*state)[1] = z2;
+ (*state)[2] = z3;
+ (*state)[3] = z4;
+
+ b = b & 0xFFFFFFFF;
+
+ return((uint32_t) 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.
+ *
+ * @param[in] seed user supplied seed value for the RNG
+ * @param[out] state state of the RNG
+ */
+void lfsr113_seed(uint32_t seed, uint64_t **state)
+{
+ uint64_t z1 = 2,
+ z2 = 8,
+ z3 = 16,
+ z4 = 128;
+
+ 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(uint64_t)*4);
+ }
+
+ (*state)[0] = z1;
+ (*state)[1] = z2;
+ (*state)[2] = z3;
+ (*state)[3] = z4;
+}
+
+#ifdef TARGETPYTHON
+/*
+ *
+ * Start of Python code
+ *
+ */
+
+static PyObject *_syncrng_seed(PyObject *self, PyObject *args)
+{
+ uint32_t seed;
+ uint64_t *state = NULL;
+
+ PyObject *dblObj;
+
+ if (!PyArg_ParseTuple(args, "O", &dblObj))
+ return NULL;
+
+ seed = (uint32_t) PyLong_AsLong(dblObj);
+ lfsr113_seed(seed, &state);
+
+ PyObject *pystate = Py_BuildValue("[d, d, d, d, d]",
+ (double) state[0],
+ (double) state[1],
+ (double) state[2],
+ (double) state[3],
+ -1.0);
+ free(state);
+ return pystate;
+}
+
+static PyObject *_syncrng_rand(PyObject *self, PyObject *args)
+{
+ int i;
+ uint32_t rand;
+ uint64_t *localstate = malloc(sizeof(uint64_t) * 4);
+
+ PyObject *listObj;
+ PyObject *dblObj;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &listObj))
+ return NULL;
+
+ for (i=0; i<4; i++) {
+ dblObj = PyList_GetItem(listObj, i);
+ localstate[i] = (uint64_t) PyFloat_AS_DOUBLE(dblObj);
+ }
+
+ rand = lfsr113(&localstate);
+
+ PyObject *pystate = Py_BuildValue("[d, d, d, d, d]",
+ (double) localstate[0],
+ (double) localstate[1],
+ (double) localstate[2],
+ (double) localstate[3],
+ (double) 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}
+};
+
+#if PY_MAJOR_VERSION >= 3
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "_syncrng",
+ "Python interface to SyncRNG",
+ -1,
+ SyncRNGMethods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+#endif
+
+
+static PyObject *
+moduleinit(void)
+{
+ PyObject *m;
+
+ #if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&moduledef);
+ #else
+ m = Py_InitModule3("_syncrng", SyncRNGMethods,
+ "Python interface to SyncRNG");
+ #endif
+
+ return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC
+PyInit__syncrng(void)
+{
+ return moduleinit();
+}
+#else
+PyMODINIT_FUNC
+init_syncrng(void)
+{
+ moduleinit();
+}
+#endif
+#endif
+
+#ifndef TARGETPYTHON
+
+/*
+ *
+ * Start of R code
+ *
+ */
+
+SEXP R_syncrng_seed(SEXP seed);
+SEXP R_syncrng_rand(SEXP state);
+
+R_CallMethodDef callMethods[] = {
+ {"R_syncrng_seed", (DL_FUNC) &R_syncrng_seed, 1},
+ {"R_syncrng_rand", (DL_FUNC) &R_syncrng_seed, 1},
+ {NULL, NULL, 0}
+};
+R_CMethodDef cMethods[] = {
+ {NULL, NULL, 0}
+};
+
+void R_init_myLib(DllInfo *info)
+{
+ R_registerRoutines(info, cMethods, callMethods, NULL, NULL);
+ R_useDynamicSymbols(info, TRUE);
+}
+
+// Set the seed for the generator from the reference class
+SEXP R_syncrng_seed(SEXP seed)
+{
+ int i;
+ double *pseed = REAL(seed),
+ *pstate = NULL;
+ uint32_t useed = (uint32_t) *pseed;
+ uint64_t *state = NULL;
+
+ lfsr113_seed(useed, &state);
+
+ SEXP Rstate = PROTECT(allocVector(REALSXP, 5));
+ pstate = REAL(Rstate);
+ for (i=0; i<4; i++) {
+ pstate[i] = (double) state[i];
+ }
+ pstate[4] = -1.0;
+ free(state);
+
+ UNPROTECT(1);
+ return Rstate;
+}
+
+// get a random number from the reference class
+SEXP R_syncrng_rand(SEXP state)
+{
+ uint64_t *localstate = malloc(sizeof(uint64_t)*4);
+ double *pstate = REAL(state);
+ int i;
+ for (i=0; i<4; i++) {
+ localstate[i] = (uint64_t) pstate[i];
+ }
+
+ uint32_t rand = lfsr113(&localstate);
+
+ SEXP Rstate = PROTECT(allocVector(REALSXP, 5));
+ pstate = REAL(Rstate);
+
+ for (i=0; i<4; i++) {
+ pstate[i] = (double) localstate[i];
+ }
+ pstate[4] = (double) rand;
+ UNPROTECT(1);
+
+ free(localstate);
+
+ return Rstate;
+}
+
+/*
+ * The following code is used to make SyncRNG a real "user-defined" RNG
+ * follwing .Random.user documentation.
+ *
+ */
+
+static uint32_t global_R_seed;
+static uint32_t global_R_nseed = 1;
+static double global_R_result_uniform;
+static double global_R_result_normal;
+static uint64_t *global_R_state = NULL;
+
+double *user_unif_rand()
+{
+ if (global_R_state == NULL) {
+ // if it's not seeded yet we seed it with 0
+ global_R_seed = 0;
+ lfsr113_seed(global_R_seed, &global_R_state);
+ }
+
+ uint32_t rand = lfsr113(&global_R_state);
+ global_R_result_uniform = rand * 2.3283064365387e-10;
+ return &global_R_result_uniform;
+}
+
+// see: https://stackoverflow.com/q/47824450/1154005
+Int32 _unscramble(Int32 scram)
+{
+ int j;
+ for (j=0; j<50; j++) {
+ scram = ((scram - 1) * 2783094533);
+ }
+ return scram;
+}
+
+// note that Int32 is "unsigned int" which is not necessarily 32 bit
+void user_unif_init(Int32 seed_in)
+{
+ global_R_seed = seed_in;
+ uint32_t useed = _unscramble(seed_in);
+
+ // destroy the previous state, we're reseeding the RNG
+ if (global_R_state != NULL) {
+ free(global_R_state);
+ global_R_state = NULL;
+ }
+ lfsr113_seed(useed, &global_R_state);
+}
+
+int *user_unif_nseed()
+{
+ return &global_R_nseed;
+}
+
+int *user_unif_seedloc()
+{
+ return (int *) &global_R_seed;
+}
+
+double *user_norm_rand()
+{
+ double u, v, z, x;
+ do {
+ u = *user_unif_rand();
+ v = 0.857764 * (2. * (*user_unif_rand()) - 1);
+ x = v/u;
+ z = 0.25 * x * x;
+ if (z < 1. - u)
+ break;
+ if (z > 0.259/u + 0.35)
+ continue;
+ } while (z > -log(u));
+ global_R_result_normal = x;
+ return &global_R_result_normal;
+}
+
+/*
+ *
+ * End of R code
+ *
+ */
+#endif
diff --git a/R/src/syncrng.c b/R/src/syncrng.c
new file mode 100644
index 0000000..3a8cf68
--- /dev/null
+++ b/R/src/syncrng.c
@@ -0,0 +1,407 @@
+#ifdef TARGETPYTHON
+#include "Python.h"
+#include <stdint.h>
+#endif
+
+#ifndef TARGETPYTHON
+#define STRICT_R_HEADERS
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <R.h>
+#include <Rinternals.h>
+#include <R_ext/Random.h>
+#include <R_ext/Rdynload.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 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},
+ * 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
+ */
+uint32_t lfsr113(uint64_t **state)
+{
+ uint64_t z1, z2, z3, z4;
+ uint64_t 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;
+ (*state)[1] = z2;
+ (*state)[2] = z3;
+ (*state)[3] = z4;
+
+ b = b & 0xFFFFFFFF;
+
+ return((uint32_t) 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.
+ *
+ * @param[in] seed user supplied seed value for the RNG
+ * @param[out] state state of the RNG
+ */
+void lfsr113_seed(uint32_t seed, uint64_t **state)
+{
+ uint64_t z1 = 2,
+ z2 = 8,
+ z3 = 16,
+ z4 = 128;
+
+ 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(uint64_t)*4);
+ }
+
+ (*state)[0] = z1;
+ (*state)[1] = z2;
+ (*state)[2] = z3;
+ (*state)[3] = z4;
+}
+
+#ifdef TARGETPYTHON
+/*
+ *
+ * Start of Python code
+ *
+ */
+
+static PyObject *_syncrng_seed(PyObject *self, PyObject *args)
+{
+ uint32_t seed;
+ uint64_t *state = NULL;
+<<<<<<< HEAD:new_R/src/syncrng.c
+=======
+
+ PyObject *dblObj;
+>>>>>>> python:new_python/src/_syncrng.c
+
+ if (!PyArg_ParseTuple(args, "O", &dblObj))
+ return NULL;
+
+ seed = (uint32_t) PyLong_AsLong(dblObj);
+ lfsr113_seed(seed, &state);
+
+ PyObject *pystate = Py_BuildValue("[d, d, d, d, d]",
+ (double) state[0],
+ (double) state[1],
+ (double) state[2],
+ (double) state[3],
+ -1.0);
+ free(state);
+ return pystate;
+}
+
+static PyObject *_syncrng_rand(PyObject *self, PyObject *args)
+{
+<<<<<<< HEAD:new_R/src/syncrng.c
+ uint32_t i, value, numints;
+ uint64_t *localstate;
+=======
+ int i;
+ uint32_t rand;
+ uint64_t *localstate = malloc(sizeof(uint64_t) * 4);
+>>>>>>> python:new_python/src/_syncrng.c
+
+ PyObject *listObj;
+ PyObject *dblObj;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &listObj))
+ return NULL;
+
+<<<<<<< HEAD:new_R/src/syncrng.c
+ // we're just assuming you would never pass more than 4 values
+ localstate = malloc(sizeof(uint32_t)*5);
+ numints = PyList_Size(listObj);
+ for (i=0; i<numints; i++) {
+ intObj = PyList_GetItem(listObj, i);
+ value = (uint32_t) PyLong_AsLong(intObj);
+ localstate[i] = value;
+ }
+
+ uint32_t rand = lfsr113(&localstate);
+ localstate[4] = rand;
+=======
+ for (i=0; i<4; i++) {
+ dblObj = PyList_GetItem(listObj, i);
+ localstate[i] = (uint64_t) PyFloat_AS_DOUBLE(dblObj);
+ }
+
+ rand = lfsr113(&localstate);
+>>>>>>> python:new_python/src/_syncrng.c
+
+ PyObject *pystate = Py_BuildValue("[d, d, d, d, d]",
+ (double) localstate[0],
+ (double) localstate[1],
+ (double) localstate[2],
+ (double) localstate[3],
+ (double) 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}
+};
+
+#if PY_MAJOR_VERSION >= 3
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "_syncrng",
+ "Python interface to SyncRNG",
+ -1,
+ SyncRNGMethods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+#endif
+
+
+static PyObject *
+moduleinit(void)
+{
+ PyObject *m;
+
+ #if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&moduledef);
+ #else
+ m = Py_InitModule3("_syncrng", SyncRNGMethods,
+ "Python interface to SyncRNG");
+ #endif
+
+ return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC
+PyInit__syncrng(void)
+{
+ return moduleinit();
+}
+#else
+PyMODINIT_FUNC
+init_syncrng(void)
+{
+ moduleinit();
+}
+#endif
+#endif
+
+#ifndef TARGETPYTHON
+
+/*
+ *
+ * Start of R code
+ *
+ */
+
+SEXP R_syncrng_seed(SEXP seed);
+SEXP R_syncrng_rand(SEXP state);
+
+R_CallMethodDef callMethods[] = {
+ {"R_syncrng_seed", (DL_FUNC) &R_syncrng_seed, 1},
+ {"R_syncrng_rand", (DL_FUNC) &R_syncrng_seed, 1},
+ {NULL, NULL, 0}
+};
+R_CMethodDef cMethods[] = {
+ {NULL, NULL, 0}
+};
+
+void R_init_myLib(DllInfo *info)
+{
+ R_registerRoutines(info, cMethods, callMethods, NULL, NULL);
+ R_useDynamicSymbols(info, TRUE);
+}
+
+// Set the seed for the generator from the reference class
+SEXP R_syncrng_seed(SEXP seed)
+{
+ int i;
+ double *pseed = REAL(seed),
+ *pstate = NULL;
+ uint32_t useed = (uint32_t) *pseed;
+ uint64_t *state = NULL;
+
+ lfsr113_seed(useed, &state);
+
+ SEXP Rstate = PROTECT(allocVector(REALSXP, 5));
+ pstate = REAL(Rstate);
+ for (i=0; i<4; i++) {
+ pstate[i] = (double) state[i];
+ }
+ pstate[4] = -1.0;
+ free(state);
+
+ UNPROTECT(1);
+ return Rstate;
+}
+
+// get a random number from the reference class
+SEXP R_syncrng_rand(SEXP state)
+{
+ uint64_t *localstate = malloc(sizeof(uint64_t)*4);
+ double *pstate = REAL(state);
+ int i;
+ for (i=0; i<4; i++) {
+ localstate[i] = (uint64_t) pstate[i];
+ }
+
+ uint32_t rand = lfsr113(&localstate);
+
+ SEXP Rstate = PROTECT(allocVector(REALSXP, 5));
+ pstate = REAL(Rstate);
+
+ for (i=0; i<4; i++) {
+ pstate[i] = (double) localstate[i];
+ }
+ pstate[4] = (double) rand;
+ UNPROTECT(1);
+
+ free(localstate);
+
+ return Rstate;
+}
+
+/*
+ * The following code is used to make SyncRNG a real "user-defined" RNG
+ * follwing .Random.user documentation.
+ *
+ */
+
+static uint32_t global_R_seed;
+<<<<<<< HEAD:new_R/src/syncrng.c
+static int global_R_nseed = 1;
+=======
+static uint32_t global_R_nseed = 1;
+>>>>>>> python:new_python/src/_syncrng.c
+static double global_R_result_uniform;
+static double global_R_result_normal;
+static uint64_t *global_R_state = NULL;
+
+double *user_unif_rand()
+{
+ if (global_R_state == NULL) {
+ // if it's not seeded yet we seed it with 0
+ global_R_seed = 0;
+ lfsr113_seed(global_R_seed, &global_R_state);
+ }
+
+ uint32_t rand = lfsr113(&global_R_state);
+ global_R_result_uniform = rand * 2.3283064365387e-10;
+ return &global_R_result_uniform;
+}
+
+// see: https://stackoverflow.com/q/47824450/1154005
+Int32 _unscramble(Int32 scram)
+{
+ int j;
+ for (j=0; j<50; j++) {
+ scram = ((scram - 1) * 2783094533);
+ }
+ return scram;
+}
+
+// note that Int32 is "unsigned int" which is not necessarily 32 bit
+void user_unif_init(Int32 seed_in)
+{
+ global_R_seed = seed_in;
+ uint32_t useed = _unscramble(seed_in);
+
+ // destroy the previous state, we're reseeding the RNG
+ if (global_R_state != NULL) {
+ free(global_R_state);
+ global_R_state = NULL;
+ }
+ lfsr113_seed(useed, &global_R_state);
+}
+
+int *user_unif_nseed()
+{
+ return &global_R_nseed;
+}
+
+int *user_unif_seedloc()
+{
+ return (int *) &global_R_seed;
+}
+
+double *user_norm_rand()
+{
+ double u, v, z, x;
+ do {
+ u = *user_unif_rand();
+ v = 0.857764 * (2. * (*user_unif_rand()) - 1);
+ x = v/u;
+ z = 0.25 * x * x;
+ if (z < 1. - u)
+ break;
+ if (z > 0.259/u + 0.35)
+ continue;
+ } while (z > -log(u));
+ global_R_result_normal = x;
+ return &global_R_result_normal;
+}
+
+/*
+ *
+ * End of R code
+ *
+ */
+#endif
diff --git a/R/tests/testthat.R b/R/tests/testthat.R
new file mode 100644
index 0000000..b1f5cc8
--- /dev/null
+++ b/R/tests/testthat.R
@@ -0,0 +1,4 @@
+library(testthat)
+library(SyncRNG)
+
+test_check("SyncRNG")
diff --git a/R/tests/testthat/first_1000_seed_0.txt b/R/tests/testthat/first_1000_seed_0.txt
new file mode 100644
index 0000000..50aef45
--- /dev/null
+++ b/R/tests/testthat/first_1000_seed_0.txt
@@ -0,0 +1,1000 @@
+1574944
+268744
+33556004
+8390676
+16851968
+2147582472
+134350084
+1074315269
+2097666
+2693283843
+50598144
+402792448
+536872117
+2281705500
+2097216
+67127296
+1192
+4097
+413712
+68096
+537198610
+9502976
+1077936653
+23069188
+256
+271065282
+1375735819
+1075056808
+137344
+537396752
+71370760
+134520872
+3196164
+24836
+2164785857
+2183397387
+269344
+41977872
+943785105
+2195975
+2283815708
+3170454
+68182051
+2281710785
+34344960
+1074024480
+460824
+839122944
+7438364
+155238412
+2166440334
+67126401
+3489693830
+1124336267
+537284650
+8392144
+805381657
+2165408
+29452
+2146516
+33704323
+2148282537
+19138624
+1619267616
+33754640
+671155715
+549519625
+3422584857
+7889684
+12289
+3223323809
+302387200
+1334448
+12654616
+940410368
+69321472
+205808168
+2167956679
+422150
+3506449091
+3263561808
+1350900792
+6425240
+809550976
+543263112
+203481359
+2146694
+1196512
+3355967617
+61734977
+8853552
+46403088
+704741917
+540082961
+2365612954
+2149671132
+117458370
+2147925124
+59121344
+1342640170
+4362072
+805610753
+5308846
+37785610
+20730196
+28992
+2952790235
+1082458123
+466480
+10487956
+1006651158
+11135872
+1241543311
+3229405863
+84162883
+2687116417
+308610137
+1217697952
+34756884
+940057617
+2757853260
+2281750584
+2117046
+8536213
+2432762497
+2200211979
+143004704
+9555090
+541402267
+2688090691
+140792396
+18901124
+34619827
+2281975939
+1126991882
+1611028540
+1510426
+570433665
+4261976
+201367560
+2151409932
+159745
+2416476396
+36078209
+545545526
+47188314
+570525328
+540398565
+2231400988
+2688182423
+359426
+3489672937
+10915924
+1409751076
+8104090
+805697154
+1089569002
+1296220170
+23228310
+71304648
+3357573835
+1402388746
+68628924
+2161655515
+571323533
+1144329024
+226905022
+807660740
+123848654
+3507419777
+2206633420
+1879528495
+39521946
+675329344
+4260201
+2342551838
+4160788
+1080928
+2952791293
+42848321
+350126
+2159872543
+1023504852
+4190932
+171990682
+1631541431
+19363907
+3758286790
+1113949782
+1845794863
+948310
+536886913
+3764488345
+17297420
+2279406
+81939869
+2349451169
+18637697
+243556660
+3263987441
+705043609
+3232571140
+3385285445
+946061980
+106022815
+2149881281
+2466519302
+1645367474
+918576
+546053696
+877659196
+216334888
+154739468
+70398851
+3707790308
+1107714240
+41949434
+3234631865
+960994496
+271830786
+205637392
+2285371587
+68563108
+3355977792
+2192441361
+1367412784
+40143408
+981517841
+543196563
+2367734299
+2283872410
+1344
+2181071879
+2206859904
+553846898
+549654344
+805609997
+2163104
+71332746
+86007956
+117991874
+3490064554
+25562218
+1879511088
+4425864
+541165322
+146901518
+1242620175
+75297540
+2148145409
+2687242416
+1386547200
+1515192
+312547844
+879347469
+606675077
+2315539260
+3292288180
+84170823
+2701271680
+3259307090
+1208409120
+1231108
+805578376
+2691760719
+141869068
+86001956
+76571121
+2298545346
+53381707
+142892072
+278219778
+574726163
+2150205781
+151286350
+2250360974
+101086355
+3490494661
+1661242064
+1074073654
+34738122
+945816717
+608289773
+2232988060
+104487366
+1141132385
+3506572416
+1610914817
+12933420
+416320010
+980706718
+10825792
+3443551182
+2776525524
+335138
+3231722194
+44532831
+1421335228
+142342666
+811120154
+1147218925
+2367611246
+69654868
+4222348
+3624435928
+3551840523
+77967668
+2463755847
+706032790
+1077262534
+2376231880
+925059286
+125304554
+3624333504
+1940823454
+1887737903
+6262158
+578073551
+106029822
+182235594
+2252236174
+1678131760
+3909323963
+847760523
+552000424
+2629422019
+795718747
+3090656
+3271585593
+3845708012
+19353971
+2966053808
+1212416724
+1312070453
+235870850
+3091824202
+3269792698
+152819996
+98860412
+820192477
+2369799568
+1396620160
+244589602
+3498863850
+574856834
+3829239105
+159603286
+1067697294
+39236251
+2432997826
+721684755
+1644254266
+955946
+2695372509
+356835194
+211485320
+238662558
+1076233167
+3307891111
+3794546048
+37949562
+3637088288
+863193421
+271789329
+761391063
+205299928
+67378860
+2158013456
+3599194065
+1907079858
+174119784
+1624289467
+7483173
+2759382862
+224727064
+134258952
+3543155069
+2441640202
+2174979241
+851922069
+542448292
+3253137
+2080458461
+54616262
+252468170
+3223217159
+665218426
+4028018793
+4626772
+1748803383
+709060767
+3121149182
+56479134
+3893141625
+2686933815
+2995214218
+2162482869
+262490641
+1011561522
+549060114
+3932247987
+3223024295
+152321631
+3101843551
+1280099225
+3358647209
+252846296
+3524154097
+2187760847
+3909680653
+2179387890
+1015137433
+3494929304
+50606464
+3901100357
+9850320
+940382251
+2699631292
+3087385960
+9538500
+234958491
+272389742
+220260678
+2684647653
+43257408
+4027072178
+28810004
+2101495309
+18607774
+134280454
+3223347501
+1376157898
+3222543805
+22419610
+973776048
+83221848
+218483748
+2685071319
+134550656
+3506980865
+2173075612
+2483766325
+66860762
+138671625
+1075841013
+2367832091
+2247808
+38814954
+3490485897
+60737793
+604469508
+2153524819
+536917141
+1074075984
+12724890
+2972321868
+23188040
+1074423975
+1117820684
+1879381029
+1739586
+939530176
+5327050
+58757130
+2151669013
+67532608
+3087534325
+2474001
+277224382
+2191034903
+1057240535
+549434183
+3405807240
+1618369262
+86191107
+2955045761
+308647117
+1578408101
+3139990
+806116500
+3831595195
+155443373
+19022846
+98715033
+2634272139
+3275515777
+512124196
+3230432369
+575086366
+3225228801
+199711444
+942108876
+121867967
+2819529105
+2200767815
+1921129010
+36410428
+780163669
+274212015
+2376151708
+3359123316
+20068231
+2349001203
+2185655880
+973119224
+3235762297
+755212101
+2956716003
+103138961
+3376199891
+92680340
+3758301290
+3236398675
+1090770984
+4196670
+813793301
+16288768
+1277219531
+140550882
+25313600
+3257601090
+2477397505
+429066492
+583196168
+671646619
+2754150662
+2399163262
+69629076
+101346518
+3775145624
+3282507882
+1619334952
+6457996
+637846925
+676180878
+175175818
+1698451828
+2233162017
+3087408874
+49089607
+478663992
+280881932
+945942552
+3224705271
+151407497
+607767788
+80172123
+3624479885
+1110753748
+2013690146
+2184431875
+709117454
+2692553290
+2157242825
+874605844
+86108881
+2567065312
+1092017287
+344356159
+2425400907
+574662615
+1084594274
+1262643867
+929455814
+56999307
+2821124246
+858115549
+1888834109
+2150800911
+627861145
+6024170
+228373816
+1178327534
+1093027685
+3624421308
+3798255747
+449290167
+2597181707
+926243929
+2687439124
+254107214
+3829027460
+93803542
+3968018064
+1388720668
+1151812149
+1214147364
+844558349
+1080633195
+2350576007
+2368200508
+97528200
+2365796063
+2476535242
+1017242931
+3503925127
+852957056
+3492589682
+115795988
+925186774
+40237656
+4094491891
+1906813406
+1611043710
+1115295490
+787740617
+652006269
+3420228435
+1736435170
+1628768048
+3173066342
+1659370060
+502667371
+3701617539
+971219790
+3559002171
+3372410256
+2218574844
+14962797
+2680285584
+2318530008
+1580611180
+3962509653
+2995731663
+3262644231
+3386622672
+832903192
+826852989
+2339061594
+52616487
+319161836
+848007203
+713596765
+405804387
+2343674302
+2393126614
+2268412740
+3959609298
+3943003701
+1375818464
+3492713455
+3041590872
+1028634474
+69944722
+1329116577
+3238922414
+3508802651
+2688827650
+432118456
+181619625
+1020588554
+2158511183
+3996414429
+3430521601
+92558330
+4085981271
+3335052120
+1094411888
+943803286
+2019381420
+612050958
+739046845
+40203708
+160356556
+3241366485
+3011934011
+2552681725
+46401557
+544316860
+2897832596
+1064122014
+34062854
+3390969819
+4180831325
+2007854337
+3762749433
+174296912
+1678023203
+39792904
+3137637515
+3780663668
+688110716
+3769355130
+46416140
+3162873767
+230484689
+571417648
+3770011349
+1611628070
+2703187687
+147275591
+2556554365
+236196063
+3627157681
+2268570387
+3524220149
+2196407803
+683730648
+832718794
+958399385
+2289805767
+1393849733
+3560321216
+2190933457
+570506109
+1190464059
+855891340
+815207364
+727755671
+959944786
+2399256258
+2955296368
+2226474309
+4248919733
+54373041
+4255540140
+1079558374
+758297126
+3494062195
+172905473
+3660879546
+2169485331
+3171064613
+2734421278
+239124661
+1636792719
+1032199552
+3022143494
+1238328860
+2755367096
+1172068287
+2416030799
+1111231360
+1162238438
+136341168
+936511690
+3697688233
+2310946572
+1017208991
+3260655066
+2861019521
+4085782611
+3269494883
+820892676
+610312130
+873064187
+444719755
+1077221226
+1178295173
+2928297301
+123238584
+1803717266
+3778860833
+622164036
+2906858569
+3462751317
+230473195
+3229782038
+4056351409
+4062480954
+157481248
+15888294
+1022616105
+2251826379
+236458376
+3468433827
+3859679691
+4169609282
+3270154816
+3638739572
+3024095882
+811148317
+3261183116
+1325974504
+589588966
+546263216
+4039391440
+1001817745
+16154680
+165750980
+2788265304
+2620478124
+3439592229
+1654681662
+3608040307
+3777078995
+994394444
+1014396095
+138120475
+2685072838
+3228373358
+2552662027
+28069284
+314728824
+2426995424
+649430792
+2352053910
+2291666758
+940013010
+3257519298
+143153873
+2445086935
+895972163
+2420598353
+573867732
+1148475689
+120727570
+874272160
+1499568331
+730384503
+2381214
+272910609
+2992637073
+253053713
+84832812
+2226240734
+3876274424
+18983620
+1268799900
+1348803766
+205671635
+2826229385
+660957935
+1646191083
+103509332
+1678012033
+2713914564
+2105972745
+14594356
+278969605
+3966027377
+46113154
+1246514745
+3316402942
+990363635
+2962749314
+524577371
+3903648383
+202779778
+3762835161
+2261224091
+3692935449
+90068990
+813864789
+3496510266
+3456387596
+143015350
+315738178
+4026606747
+2176794694
+2351395438
+2264420045
+68273726
+3627034496
+1856958854
+1350988020
+58099784
+4067096716
+100097690
+1012654471
+2271403796
+1141174688
+2164427209
+562335369
+549995830
+416389002
+309413793
+11860448
+2231458885
+604433027
+251864294
+3498465912
+1401395398
+3022766621
+190641354
+139719433
+1619043956
+1125777754
+74067650
+4207624
+958432937
+1116985600
+79164300
+2419620443
+777581327
+1142807361
+63314936
+4130282535
+23324492
+554363587
+2992739718
+1208439855
+772634
+540021839
+2789338031
+163090632
+120839590
+1620336448
+2164918412
+1913539649
+141022634
+2660075661
+963507036
+2687451280
+1208246255
+2771730565
+69420323
+3233866653
+1241879628
+1723226915
+202266692
+2689359561
+1651839518
+3227502861
+78020380
+811821517
+2640397810
+18786699
+109454782
+3498917610
+542022675
+1621201984
+1220764211
+518079134
+106428047
+2150406528
+4213442838
+1712410802
+33957546
+2833255501
+1363466077
+2361205692
+238621598
+1081475811
+3290623399
+1645509834
+105086074
+1522806889
+959667661
+1344480514
+2894325459
+2637988048
+7641220
+3634424343
+2525971609
+1437315771
+174455456
+1926534907
+1080174481
+2914707278
+2355466320
+138587648
+2201502550
+3552082560
+2770463793
+818376469
+961820903
+1622385204
+3028513484
+318825118
+189698242
+3224822639
+898006137
+4135907579
+37993300
+1613862757
+1859348874
+2060448975
+35441046
+3966690161
+3037175409
+1654613515
+2255792831
+1335945969
+1023753955
+1688992272
+3938874011
+3642382007
+225770871
+2716500061
+207929882
+3426021282
+219580528
+3637400609
+3530004700
+1753898265
+166081018
+1019445811
+2555921818
+2201231873
+3422693765
+43214040
+587807866
+3506115085
+837243260
+2442251152
+240230417
+1077703104
+1327561358
+2265348349
diff --git a/R/tests/testthat/tests.R b/R/tests/testthat/tests.R
new file mode 100644
index 0000000..59dc004
--- /dev/null
+++ b/R/tests/testthat/tests.R
@@ -0,0 +1,63 @@
+library(SyncRNG)
+context("SyncRNG unit tests")
+
+test_that("test_randi", {
+ s <- SyncRNG(seed=123456)
+ expect_equal(s$randi(), 959852049)
+ expect_equal(s$randi(), 2314333085)
+ expect_equal(s$randi(), 2255782734)
+ expect_equal(s$randi(), 2921461239)
+ expect_equal(s$randi(), 1024197102)
+})
+
+test_that("test_rand", {
+ s <- SyncRNG(seed=123456)
+ expect_equal(s$rand(), 959852049 /(2**32))
+ expect_equal(s$rand(), 2314333085/(2**32))
+ expect_equal(s$rand(), 2255782734/(2**32))
+ expect_equal(s$rand(), 2921461239/(2**32))
+ expect_equal(s$rand(), 1024197102/(2**32))
+})
+
+test_that("test_randbelow", {
+ s <- SyncRNG(seed=123456)
+ expect_equal(s$randbelow(5), 4)
+ expect_equal(s$randbelow(5), 0)
+ expect_equal(s$randbelow(5), 4)
+ expect_equal(s$randbelow(5), 4)
+ expect_equal(s$randbelow(5), 2)
+})
+
+test_that("test_shuffle", {
+ s <- SyncRNG(seed=123456)
+ x <- c(1, 2, 3, 4, 5)
+ y <- s$shuffle(x)
+ expect_equal(y, c(3, 4, 1, 2, 5))
+})
+
+test_that("test_first_1000", {
+ s <- SyncRNG(seed=0)
+ fileName <- "./first_1000_seed_0.txt"
+ conn <- file(fileName, open="r")
+ linn <- readLines(conn)
+ for (i in 1:length(linn)) {
+ exp <- as.numeric(linn[i])
+ expect_equal(exp, s$randi())
+ }
+ close(conn)
+})
+
+printf <- function(...) invisible(cat(sprintf(...)));
+
+test_that("test_first_1000_unif", {
+ set.seed(0, 'user', 'user')
+ fileName <- "./first_1000_seed_0.txt"
+ conn <- file(fileName, open="r")
+ linn <- readLines(conn)
+ for (i in 1:length(linn)) {
+ exp <- as.numeric(linn[i])
+ u <- as.numeric(runif(1)*(2**32 - 1))
+ expect_equal(exp, u)
+ }
+ close(conn)
+})