Skip to content

Instantly share code, notes, and snippets.

@blixt
Last active November 5, 2021 13:42
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save blixt/9abfafdd0ada0f4f6f26 to your computer and use it in GitHub Desktop.
Save blixt/9abfafdd0ada0f4f6f26 to your computer and use it in GitHub Desktop.
Testing random number generators with DieHarder
#!/usr/bin/env node
var argv = require('minimist')(process.argv.slice(2));
// 32-bit integer conversion of the built-in RNG.
function JavaScript() {}
JavaScript.prototype.next = function () {
return Math.random() * 4294967296 >>> 0;
};
JavaScript.NUM_BITS = 32;
// Park-Miller.
function ParkMiller(seed) {
this._seed = seed % 2147483647;
if (this._seed <= 0) this._seed += 2147483646;
}
ParkMiller.NUM_BITS = 31;
ParkMiller.prototype.next = function () {
return this._seed = this._seed * 16807 % 2147483647;
};
var SEED = argv.seed || 12345,
COUNT = argv.count || 10000000,
PRNG = argv.prng || 'JavaScript';
var RandomClass = eval(PRNG);
if (!RandomClass) {
throw new Error('Invalid PRNG ' + PRNG);
}
process.stdout.write('# ' + PRNG + '\n');
process.stdout.write('# seed: ' + SEED + '\n');
process.stdout.write('type: d\n');
process.stdout.write('count: ' + COUNT + '\n');
process.stdout.write('numbit: ' + (RandomClass.NUM_BITS || 32) + '\n');
var r = new RandomClass(SEED);
for (var i = 0; i < COUNT; i++) {
var num = r.next().toString();
num = ' '.slice(0, 10 - num.length) + num;
process.stdout.write(num + '\n');
}

Testing RNGs with Dieharder

This guide is specifically for pseudo-random number generators (PRNGs) written in JavaScript, and tested in Mac OS X.

Prerequisites

Homebrew
Run this in the Terminal to install Homebrew (site):

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

Node.js
You can now use Homebrew to install Node.js (site):

brew install node

Dieharder
Homebrew also lets you install Dieharder, the tool that tests RNGs (site):

brew install dieharder

A directory for your testing
Create a directory which you'll use for testing PRNGs. This is where we'll put scripts and data.

The minimist package
A very useful package for parsing arguments which I use for the script below. Go into the testing directory and install it with NPM:

npm install minimist

Communicating with Dieharder

Dieharder can take a file as an input, so we'll use a simple Node.js script for generating a dump of random numbers. See randout.js below for a template file that implements an integer version of the built-in RNG as well as the very simple Park-Miller PRNG.

Make the file executable (chmod +x randout.js) then execute it and put its output into a file:

./randout.js > math.random.txt

Note: By default this will create 10,000,000 random numbers. That takes time and space, but is necessary for an accurate test.

And now you can test it with Dieharder:

dieharder -g 202 -f math.random.txt -a

You can read more about the dieharder tool on the Dieharder homepage, but this will run all tests on that file. Note: It will take some time!

Testing more PRNGs

You can now add more constructors for other PRNGs in randout.js. They just need a next method which returns an integer. To change which constructor is used, call the script with the --prng argument:

./randout.js --prng ParkMiller > park-miller.txt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment