# Native and non-native Random Numbers

## JavaScript performance comparison

Revision 4 of this test case created by Adam Hyland

## Preparation code

``````<script src="http://davidbau.com/encode/seedrandom-min.js"></script>
<script>

// Linear Congruential Generator
// Variant of a Lehman Generator
var lcg = (function() {
// Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes
// m is basically chosen to be large (as it is the max period)
// and for its relationships to a and c
var m = 4294967296,
// a - 1 should be divisible by m's prime factors
a = 1664525,
// c and m should be co-prime
c = 1013904223,
seed, z;
return {
setSeed : function(val) {
z = seed = val || Math.round(Math.random() * m);
},
getSeed : function() {
return seed;
},
rand : function() {
// define the recurrence relationship
z = (a * z + c) % m;
// return a float in [0, 1)
// if z = m then z / m = 0 therefore (z % m) / m < 1 always
return z / m;
}
};
}());

// Complementary Multiply-With-Carry of lag 1
// similar to Chrome's implementation (structured more traditionally)
var mwc = (function() {
// Set two seed values.
var carry, x,
// Value of modulus and multiplier are chosen together
// 2^32 is chosen because it's similar to the others
// but we don't use bitwise operations to take advantage of this
max = Math.pow(2, 32),
a = 3636507990;
return {
setSeed : function(arr) {
var seed = arr || [0,1].map(function() {
return Math.round(Math.random() * max);
});
carry = seed[0];
x = seed[1];
},
getSeed : function() {
return [carry, x];
},
rand : function() {
// Two multiplications
// create carry with division, x with mod
// The first part is the "carry" where we're
// using both parts of the residue
carry = ((a * x) + carry) / max;
// subtracting from the max is what makes it the compliment
x = (max - 1) - ((a * x) + carry) % max;
return x / max;
}
};
}());

// 16 bit Linear feedback shift register
var lsfr = (function(){
var max = Math.pow(2, 16),
period = 0,
seed, out;
return {
setSeed : function(val) {
out = seed = val || Math.round(Math.random() * max);
},
getSeed : function() {
return seed;
},
getPeriod : function() {
return period;
},
rand : function() {
var bit;
// From http://en.wikipedia.org/wiki/Linear_feedback_shift_register
bit  = ((out >> 0) ^ (out >> 2) ^ (out >> 3) ^ (out >> 5) ) & 1;
out =  (out >> 1) | (bit << 15);
period++;
return out / max;
}
};
}());

//Webkit2's crazy invertible mapping generator
var invwk = (function() {
var max = Math.pow(2, 32),
seed;
return {
setSeed : function(val) {
seed = val || Math.round(Math.random() * max);
},
getSeed : function() {
return seed;
},
rand : function() {
// creates randomness...somehow...
seed += (seed * seed) | 5;
// important because OR w/ 5 can give us + or - numbers.
return (seed >>> 32) / max;
}
};
}());

</script>

<script>
Benchmark.prototype.setup = function() {
Math.oldrand = Math.random;
Math.seedrandom();
lcg.setSeed();
mwc.setSeed();
lsfr.setSeed();
invwk.setSeed();
};

Benchmark.prototype.teardown = function() {
Math.random = Math.oldrand;
};

</script>
``````

## Preparation code output

<script> // Linear Congruential Generator // Variant of a Lehman Generator var lcg = (function() { // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes // m is basically chosen to be large (as it is the max period) // and for its relationships to a and c var m = 4294967296, // a - 1 should be divisible by m's prime factors a = 1664525, // c and m should be co-prime c = 1013904223, seed, z; return { setSeed : function(val) { z = seed = val || Math.round(Math.random() * m); }, getSeed : function() { return seed; }, rand : function() { // define the recurrence relationship z = (a * z + c) % m; // return a float in [0, 1) // if z = m then z / m = 0 therefore (z % m) / m < 1 always return z / m; } }; }()); // Complementary Multiply-With-Carry of lag 1 // similar to Chrome's implementation (structured more traditionally) var mwc = (function() { // Set two seed values. var carry, x, // Value of modulus and multiplier are chosen together // 2^32 is chosen because it's similar to the others // but we don't use bitwise operations to take advantage of this max = Math.pow(2, 32), a = 3636507990; return { setSeed : function(arr) { var seed = arr || [0,1].map(function() { return Math.round(Math.random() * max); }); carry = seed[0]; x = seed[1]; }, getSeed : function() { return [carry, x]; }, rand : function() { // Two multiplications // create carry with division, x with mod // The first part is the "carry" where we're // using both parts of the residue carry = ((a * x) + carry) / max; // subtracting from the max is what makes it the compliment x = (max - 1) - ((a * x) + carry) % max; return x / max; } }; }()); // 16 bit Linear feedback shift register var lsfr = (function(){ var max = Math.pow(2, 16), period = 0, seed, out; return { setSeed : function(val) { out = seed = val || Math.round(Math.random() * max); }, getSeed : function() { return seed; }, getPeriod : function() { return period; }, rand : function() { var bit; // From http://en.wikipedia.org/wiki/Linear_feedback_shift_register bit = ((out >> 0) ^ (out >> 2) ^ (out >> 3) ^ (out >> 5) ) & 1; out = (out >> 1) | (bit << 15); period++; return out / max; } }; }()); //Webkit2's crazy invertible mapping generator var invwk = (function() { var max = Math.pow(2, 32), seed; return { setSeed : function(val) { seed = val || Math.round(Math.random() * max); }, getSeed : function() { return seed; }, rand : function() { // creates randomness...somehow... seed += (seed * seed) | 5; // Shift off bits, discarding the sign. Discarding the sign is // important because OR w/ 5 can give us + or - numbers. return (seed >>> 32) / max; } }; }()); </script>

## Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
Native Math.random
``Math.oldrand();``
pending…
Bau's ARC4
``Math.random();``
pending…
Linear Congruential Generator
``lcg.rand();``
pending…
Multiply with Carry
``mwc.rand();``
pending…
Linear Feedback Shift Register
``lsfr.rand();``
pending…
Invertible Mapping
``invwk.rand();``
pending…

## Revisions

You can edit these tests or add even more tests to this page by appending `/edit` to the URL.