aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGertjan van den Burg <gertjanvandenburg@gmail.com>2021-01-14 17:28:56 +0000
committerGertjan van den Burg <gertjanvandenburg@gmail.com>2021-01-14 17:28:56 +0000
commit3c0568041e04412dd1ec403d12474d3ed401b600 (patch)
tree68282243d26eb93312ede8fa9983bc267da6251d
parentMerge branch 'R' (diff)
parentclean up venv_dir on make clean (diff)
downloadSyncRNG-3c0568041e04412dd1ec403d12474d3ed401b600.tar.gz
SyncRNG-3c0568041e04412dd1ec403d12474d3ed401b600.zip
Merge branch 'python'
-rw-r--r--new_R/src/_syncrng.c381
-rw-r--r--new_R/src/syncrng.c62
-rw-r--r--new_python/Makefile88
-rw-r--r--new_python/SyncRNG/__init__.py49
-rw-r--r--new_python/SyncRNG/__version__.py5
-rw-r--r--new_python/setup.py103
-rw-r--r--new_python/src/_syncrng.c407
-rw-r--r--new_python/tests/first_1000_seed_0.txt1000
-rw-r--r--new_python/tests/test_syncrng.py53
-rw-r--r--tests/first_1000_seed_0.txt1000
-rwxr-xr-xtests/run_tests.sh3
-rw-r--r--tests/test.R43
12 files changed, 3179 insertions, 15 deletions
diff --git a/new_R/src/_syncrng.c b/new_R/src/_syncrng.c
new file mode 100644
index 0000000..bd1612a
--- /dev/null
+++ b/new_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/new_R/src/syncrng.c b/new_R/src/syncrng.c
index 71fe58e..3a8cf68 100644
--- a/new_R/src/syncrng.c
+++ b/new_R/src/syncrng.c
@@ -117,33 +117,50 @@ void lfsr113_seed(uint32_t seed, uint64_t **state)
*
*/
-static PyObject *syncrng_seed(PyObject *self, PyObject *args)
+static PyObject *_syncrng_seed(PyObject *self, PyObject *args)
{
uint32_t seed;
uint64_t *state = NULL;
+<<<<<<< HEAD:new_R/src/syncrng.c
+=======
- if (!PyArg_ParseTuple(args, "k", &seed))
+ 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("[k, k, k, k]",
- state[0], state[1], state[2], state[3]);
+ 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)
+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 *intObj;
+ 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);
@@ -155,18 +172,29 @@ static PyObject *syncrng_rand(PyObject *self, PyObject *args)
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("[k, k, k, k, k]",
- localstate[0], localstate[1], localstate[2],
- localstate[3], rand);
+ 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", _syncrng_seed, METH_VARARGS,
"Seed the RNG."},
- {"rand", syncrng_rand, METH_VARARGS,
+ {"rand", _syncrng_rand, METH_VARARGS,
"Generate a single random integer using SyncRNG."},
{NULL, NULL, 0, NULL}
};
@@ -174,7 +202,7 @@ static PyMethodDef SyncRNGMethods[] = {
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
- "syncrng",
+ "_syncrng",
"Python interface to SyncRNG",
-1,
SyncRNGMethods,
@@ -194,7 +222,7 @@ moduleinit(void)
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
- m = Py_InitModule3("syncrng", SyncRNGMethods,
+ m = Py_InitModule3("_syncrng", SyncRNGMethods,
"Python interface to SyncRNG");
#endif
@@ -203,13 +231,13 @@ moduleinit(void)
#if PY_MAJOR_VERSION >= 3
PyMODINIT_FUNC
-PyInit_syncrng(void)
+PyInit__syncrng(void)
{
return moduleinit();
}
#else
PyMODINIT_FUNC
-initsyncrng(void)
+init_syncrng(void)
{
moduleinit();
}
@@ -298,7 +326,11 @@ SEXP R_syncrng_rand(SEXP state)
*/
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;
diff --git a/new_python/Makefile b/new_python/Makefile
new file mode 100644
index 0000000..940a07b
--- /dev/null
+++ b/new_python/Makefile
@@ -0,0 +1,88 @@
+#
+# Makefile for easier installation and cleanup
+#
+# Uses self-documenting macros from here:
+# http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
+#
+
+SHELL := bash
+.SHELLFLAGS := -eu -o pipefail -c
+MAKEFLAGS += --no-builtin-rules
+
+PACKAGE=SyncRNG
+VENV_DIR=/tmp/sync_venv/
+
+.PHONY: help
+
+.DEFAULT_GOAL := help
+
+help:
+ @grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) |\
+ awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m\
+ %s\n", $$1, $$2}'
+
+################
+# Installation #
+################
+
+.PHONY: inplace install
+
+inplace:
+ python setup.py build_ext --inplace
+
+install: ## Install for the current user using the default python command
+ python setup.py build_ext --inplace && \
+ python setup.py install --user
+
+################
+# Distribution #
+################
+
+.PHONY: release dist
+
+release: ## Make a release
+ python make_release.py
+
+dist: ## Make Python source distribution
+ python setup.py sdist
+
+
+###########
+# Testing #
+###########
+
+.PHONY: test
+
+test: venv ## Run nosetests using the default nosetests command
+ source $(VENV_DIR)/bin/activate && green -a -vv ./tests
+
+#######################
+# Virtual environment #
+#######################
+
+.PHONY: venv
+
+venv: $(VENV_DIR)/bin/activate
+
+$(VENV_DIR)/bin/activate:
+ test -d $(VENV_DIR) || python -m venv $(VENV_DIR)
+ source $(VENV_DIR)/bin/activate && pip install -e .[dev]
+ touch $(VENV_DIR)/bin/activate
+
+
+############
+# Clean up #
+############
+
+.PHONY: clean
+
+clean: ## Clean build dist and egg directories left after install
+ rm -rf $(VENV_DIR)
+ rm -rf ./dist ./build ./$(PACKAGE).egg-info
+ rm -rf ./build
+ rm -rf ./$(PACKAGE).egg-info
+ rm -rf *.so
+ rm -f MANIFEST
+ rm -f .coverage
+ find . -type f -iname '*.pyc' -delete
+ find . -type d -name '__pycache__' -empty -delete
diff --git a/new_python/SyncRNG/__init__.py b/new_python/SyncRNG/__init__.py
new file mode 100644
index 0000000..6d67746
--- /dev/null
+++ b/new_python/SyncRNG/__init__.py
@@ -0,0 +1,49 @@
+"""
+Simple interface to SyncRNG. This file defines a SyncRNG object which can be
+used to seed and pull numbers from the RNG.
+
+"""
+
+from copy import deepcopy
+from warnings import warn
+
+from _syncrng import seed as _seed
+from _syncrng import rand as _rand
+
+
+class SyncRNG(object):
+ def __init__(self, seed=0):
+ self.BPF = 32
+ self.seed = seed
+ self.state = _seed(self.seed)
+
+ def randi(self):
+ tmp = _rand(self.state)
+ self.state = tmp[:-1]
+ return int(tmp[-1])
+
+ def rand(self):
+ return self.randi() * 2.3283064365387e-10
+
+ def randbelow(self, n):
+ maxsize = 1 << self.BPF
+ if n >= maxsize:
+ warn(
+ "Underlying random generator does not supply \n"
+ "enough bits to choose from a population range this "
+ "large.\n"
+ )
+ return int(self.rand() * n)
+ rem = maxsize % n
+ limit = (maxsize - rem) / maxsize
+ r = self.rand()
+ while r >= limit:
+ r = self.rand()
+ return int(r * maxsize) % n
+
+ def shuffle(self, x):
+ y = deepcopy(x)
+ for i in reversed(range(1, len(y))):
+ j = self.randbelow(i + 1)
+ y[i], y[j] = y[j], y[i]
+ return y
diff --git a/new_python/SyncRNG/__version__.py b/new_python/SyncRNG/__version__.py
new file mode 100644
index 0000000..cfd0ff9
--- /dev/null
+++ b/new_python/SyncRNG/__version__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+VERSION = (1, 3 ,0)
+
+__version__ = '.'.join(map(str, VERSION))
diff --git a/new_python/setup.py b/new_python/setup.py
new file mode 100644
index 0000000..4c37187
--- /dev/null
+++ b/new_python/setup.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Setup file for SyncRNG
+
+Author: Gertjan van den Burg
+Date: Oct. 12, 2016
+"""
+
+import io
+import os
+
+from setuptools import find_packages, setup
+from distutils.extension import Extension
+
+# Package meta-data.
+AUTHOR = "Gertjan van den Burg"
+DESCRIPTION = "Generate the same random numbers in R and Python"
+EMAIL = "gertjanvandenburg@gmail.com"
+LICENSE = "GPLv2"
+LICENSE_TROVE = "License :: OSI Approved :: GNU General Public License v2 (GPLv2)"
+NAME = "SyncRNG"
+REQUIRES_PYTHON = ">=3.6.0"
+URL = "https://github.com/GjjvdBurg/SyncRNG"
+VERSION = None
+
+# What packages are required for this module to be executed?
+REQUIRED = []
+
+docs_require = []
+test_require = []
+dev_require = ["green"]
+
+# What packages are optional?
+EXTRAS = {
+ "docs": docs_require,
+ "test": test_require,
+ "dev": docs_require + test_require + dev_require,
+}
+
+# The rest you shouldn't have to touch too much :)
+# ------------------------------------------------
+# Except, perhaps the License and Trove Classifiers!
+# If you do change the License, remember to change the Trove Classifier for that!
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+# Import the README and use it as the long-description.
+# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
+try:
+ with io.open(os.path.join(here, "README.md"), encoding="utf-8") as f:
+ long_description = "\n" + f.read()
+except FileNotFoundError:
+ long_description = DESCRIPTION
+
+# Load the package's __version__.py module as a dictionary.
+about = {}
+if not VERSION:
+ project_slug = NAME.replace("-", "_").replace(" ", "_")
+ with open(os.path.join(here, project_slug, "__version__.py")) as f:
+ exec(f.read(), about)
+else:
+ about["__version__"] = VERSION
+
+# Where the magic happens:
+setup(
+ name=NAME,
+ version=about["__version__"],
+ description=DESCRIPTION,
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ author=AUTHOR,
+ author_email=EMAIL,
+ python_requires=REQUIRES_PYTHON,
+ url=URL,
+ packages=find_packages(
+ exclude=["tests", "*.tests", "*.tests.*", "tests.*"]
+ ),
+ install_requires=REQUIRED,
+ extras_require=EXTRAS,
+ include_package_data=True,
+ license=LICENSE,
+ ext_modules=[
+ Extension(
+ "_syncrng",
+ define_macros=[('TARGETPYTHON', '1')],
+ sources=["src/_syncrng.c"],
+ extra_compile_args=['-g']
+ )
+ ],
+ classifiers=[
+ # Trove classifiers
+ # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
+ LICENSE_TROVE,
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Science/Research',
+ 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Topic :: Scientific/Engineering :: Mathematics'
+ ],
+)
diff --git a/new_python/src/_syncrng.c b/new_python/src/_syncrng.c
new file mode 100644
index 0000000..3a8cf68
--- /dev/null
+++ b/new_python/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/new_python/tests/first_1000_seed_0.txt b/new_python/tests/first_1000_seed_0.txt
new file mode 100644
index 0000000..50aef45
--- /dev/null
+++ b/new_python/tests/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/new_python/tests/test_syncrng.py b/new_python/tests/test_syncrng.py
new file mode 100644
index 0000000..58b504d
--- /dev/null
+++ b/new_python/tests/test_syncrng.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+
+import os
+import unittest
+
+from SyncRNG import SyncRNG
+
+
+class SyncRNGTestCase(unittest.TestCase):
+ def test_randi(self):
+ s = SyncRNG(seed=123456)
+ self.assertEqual(s.randi(), 959852049)
+ self.assertEqual(s.randi(), 2314333085)
+ self.assertEqual(s.randi(), 2255782734)
+ self.assertEqual(s.randi(), 2921461239)
+ self.assertEqual(s.randi(), 1024197102)
+
+ def test_rand(self):
+ s = SyncRNG(seed=123456)
+ self.assertAlmostEqual(s.rand(), 959852049 / pow(2, 32))
+ self.assertAlmostEqual(s.rand(), 2314333085 / pow(2, 32))
+ self.assertAlmostEqual(s.rand(), 2255782734 / pow(2, 32))
+ self.assertAlmostEqual(s.rand(), 2921461239 / pow(2, 32))
+ self.assertAlmostEqual(s.rand(), 1024197102 / pow(2, 32))
+
+ def test_randbelow(self):
+ s = SyncRNG(seed=123456)
+ self.assertEqual(s.randbelow(5), 4)
+ self.assertEqual(s.randbelow(5), 0)
+ self.assertEqual(s.randbelow(5), 4)
+ self.assertEqual(s.randbelow(5), 4)
+ self.assertEqual(s.randbelow(5), 2)
+
+ def test_shuffle(self):
+ s = SyncRNG(seed=123456)
+ x = [1, 2, 3, 4, 5]
+ y = s.shuffle(x)
+ self.assertEqual(y, [3, 4, 1, 2, 5])
+
+ def test_first_1000(self):
+ s = SyncRNG(seed=0)
+
+ here = os.path.dirname(__file__)
+ test_file = os.path.join(here, "first_1000_seed_0.txt")
+
+ with open(test_file, "r") as fid:
+ for line in fid:
+ exp = int(line.strip())
+ self.assertTrue(exp == s.randi())
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/first_1000_seed_0.txt b/tests/first_1000_seed_0.txt
new file mode 100644
index 0000000..50aef45
--- /dev/null
+++ b/tests/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/tests/run_tests.sh b/tests/run_tests.sh
new file mode 100755
index 0000000..4c7c5da
--- /dev/null
+++ b/tests/run_tests.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+paste <(python test.py) <(Rscript test.R)
diff --git a/tests/test.R b/tests/test.R
new file mode 100644
index 0000000..0937f52
--- /dev/null
+++ b/tests/test.R
@@ -0,0 +1,43 @@
+library(SyncRNG)
+
+test.randi <- function()
+{
+ s <- SyncRNG(seed=123456)
+ for (i in 1:5)
+ cat(s$randi(), '\n')
+}
+
+test.rand <- function()
+{
+ s <- SyncRNG(seed=123456)
+ for (i in 1:5)
+ cat(sprintf('%.16f\n', s$rand()))
+}
+
+test.randbelow <- function()
+{
+ s <- SyncRNG(seed=123456)
+ for (i in 1:5)
+ cat(s$randbelow(i), '\n')
+}
+
+test.shuffle <- function()
+{
+ s <- SyncRNG(seed=123456)
+ x <- c(1:5)
+ for (i in 1:5) {
+ y <- s$shuffle(x)
+ x <- y
+ cat('[', paste(y, collapse=', '), ']\n', sep='')
+ }
+}
+
+main <- function()
+{
+ test.randi()
+ test.rand()
+ test.randbelow()
+ test.shuffle()
+}
+
+main()