Pseudo Random Number Generators

JavaScript performance comparison

Revision 4 of this test case created by inglorion

Info

Tests different PRNGs in JavaScript

Preparation code

<script>
// DeadbeefRand: http://inglorion.net/software/deadbeef_rand/
function DeadbeefRand(seed) {
    var beef = 0xdeadbeef;

    this.rand = function () {
        seed = ((seed << 7) ^ ((seed >> 25 & 0x7f) + beef));
        if(seed < 0) seed += 0x100000000;
        beef = ((beef << 7) ^ ((beef >> 25 & 0x7f) + 0xdeadbeef));
        return seed;
    }
}

// Mash: http://baagoe.org/en/wiki/Mash
function Mash() {
    var n = 0xefc8249d;
 
    var mash = function(data) {
      data = data.toString();
      for (var i = 0; i < data.length; i++) {
        n += data.charCodeAt(i);
        var h = 0.02519603282416938 * n;
        n = h >>> 0;
        h -= n;
        h *= n;
        n = h >>> 0;
        h -= n;
        n += h * 0x100000000; // 2^32
      }
      return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
    };
 
    mash.version = 'Mash 0.9';
    return mash;
  }

// MRG32k3a: http://baagoe.org/en/wiki/MRG32k3a
 function MRG32k3a() {
    return (function(args) {
      // Copyright (c) 1998, 2002 Pierre L'Ecuyer, DIRO, Université de Montréal.
      // http://www.iro.umontreal.ca/~lecuyer/
      var m1 = 4294967087;
      var m2 = 4294944443;
      var s10 = 12345,
          s11 = 12345,
          s12 = 123,
          s20 = 12345,
          s21 = 12345,
          s22 = 123;
 
      if (args.length === 0) {
        args = [+new Date()];
      }
      var mash = Mash();
      for (var i = 0; i < args.length; i++) {
        s10 += mash(args[i]) * 0x100000000; // 2 ^ 32
        s11 += mash(args[i]) * 0x100000000;
        s12 += mash(args[i]) * 0x100000000;
        s20 += mash(args[i]) * 0x100000000;
        s21 += mash(args[i]) * 0x100000000;
        s22 += mash(args[i]) * 0x100000000;
      }
      s10 %= m1;
      s11 %= m1;
      s12 %= m1;
      s20 %= m2;
      s21 %= m2;
      s22 %= m2;
      mash = null;
 
      var uint32 = function() {
        var m1 = 4294967087;
        var m2 = 4294944443;
        var a12 = 1403580;
        var a13n = 810728;
        var a21 = 527612;
        var a23n = 1370589;
 
        var k, p1, p2;
 
        /* Component 1 */
        p1 = a12 * s11 - a13n * s10;
        k = p1 / m1 | 0;
        p1 -= k * m1;
        if (p1 < 0) p1 += m1;
        s10 = s11;
        s11 = s12;
        s12 = p1;
 
        /* Component 2 */
        p2 = a21 * s22 - a23n * s20;
        k = p2 / m2 | 0;
        p2 -= k * m2;
        if (p2 < 0) p2 += m2;
        s20 = s21;
        s21 = s22;
        s22 = p2;
 
        /* Combination */
        if (p1 <= p2) return p1 - p2 + m1;
        else return p1 - p2;
      };
 
      var random = function() {
        return uint32() * 2.3283064365386963e-10; // 2^-32
      };
      random.uint32 = uint32;
      random.fract53 = function() {
        return random() +
          (uint32() & 0x1fffff) * 1.1102230246251565e-16; // 2^-53
      };
      random.version = 'MRG32k3a 0.9';
      random.args = args;
 
      return random;
    } (Array.prototype.slice.call(arguments)));
  };

// Xorshift03: http://baagoe.org/en/wiki/Xorshift03
function Xorshift03() {
    return (function(args) {
      // George Marsaglia, 13 May 2003
      // http://groups.google.com/group/comp.lang.c/msg/e3c4ea1169e463ae
      var x = 123456789,
          y = 362436069,
          z = 521288629,
          w = 88675123,
          v = 886756453;
 
      if (args.length == 0) {
        args = [+new Date];
      }
      var mash = Mash();
      for (var i = 0; i < args.length; i++) {
        x ^= mash(args[i]) * 0x100000000; // 2^32
        y ^= mash(args[i]) * 0x100000000;
        z ^= mash(args[i]) * 0x100000000;
        v ^= mash(args[i]) * 0x100000000;
        w ^= mash(args[i]) * 0x100000000;
      }
      mash = null;
 
      var uint32 = function() {
        var t = (x ^ (x >>> 7)) >>> 0;
        x = y;
        y = z;
        z = w;
        w = v;
        v = (v ^ (v << 6)) ^ (t ^ (t << 13)) >>> 0;
        return ((y + y + 1) * v) >>> 0;
      }
 
      var random = function() {
        return uint32() * 2.3283064365386963e-10; // 2^-32
      };
      random.uint32 = uint32;
      random.fract53 = function() {
        return random() +
          (uint32() & 0x1fffff) * 1.1102230246251565e-16; // 2^-53
      };
      random.version = 'Xorshift03 0.9';
      random.args = args;
      return random;
 
    } (Array.prototype.slice.call(arguments)));
  };

// KISS07: http://baagoe.org/en/wiki/KISS07
function KISS07() {
    return (function(args) {
      // George Marsaglia, 2007-06-23
      //http://groups.google.com/group/comp.lang.fortran/msg/6edb8ad6ec5421a5
      var x = 123456789;
      var y = 362436069;
      var z =  21288629;
      var w =  14921776;
      var c = 0;
 
      if (args.length == 0) {
        args = [+new Date];
      }
      var mash = Mash();
      for (var i = 0; i < args.length; i++) {
        x ^= mash(args[i]) * 0x100000000; // 2^32
        y ^= mash(args[i]) * 0x100000000;
        z ^= mash(args[i]) * 0x100000000;
        w ^= mash(args[i]) * 0x100000000;
      }
      if (y === 0) {
        y = 1;
      }
      c ^= z >>> 31;
      z &= 0x7fffffff;
      if ((z % 7559) === 0) {
        z++;
      }
      w &= 0x7fffffff;
      if ((w % 7559) === 0) {
        w++;
      }
      mash = null;
 
      var uint32 = function() {
        var t;
 
        x += 545925293;
        x >>>= 0;
 
        y ^= y << 13;
        y ^= y >>> 17;
        y ^= y << 5;
 
        t = z + w + c;
        z = w;
        c = t >>> 31;
        w = t & 0x7fffffff;
 
        return x + y + w >>> 0;
      };
 
      var random = function() {
        return uint32() * 2.3283064365386963e-10; // 2^-32
      };
      random.uint32 = uint32;
      random.fract53 = function() {
        return random() +
          (uint32() & 0x1fffff) * 1.1102230246251565e-16; // 2^-53
      };
      random.args = args;
      random.version = 'KISS07 0.9';
 
      return random;
    } (Array.prototype.slice.call(arguments)));
  };

// LFib: http://baagoe.org/en/wiki/LFib
function LFib() {
    return (function(args) {
      var k0 = 255,
          k1 = 52,
          k2 = 0;
      var s = [];
 
      var mash = Mash();
      if (args.length === 0) {
        args = [+new Date()];
      }
      for (var j = 0; j < 256; j++) {
        s[j] = mash(' ');
        s[j] -= mash(' ') * 4.76837158203125e-7; // 2^-21
        if (s[j] < 0) {
          s[j] += 1;
        }
      }
      for (var i = 0; i < args.length; i++) {
        for (var j = 0; j < 256; j++) {
          s[j] -= mash(args[i]);
          s[j] -= mash(args[i]) * 4.76837158203125e-7; // 2^-21
          if (s[j] < 0) {
            s[j] += 1;
          }
        }
      }
      mash = null;
 
      var random = function() {
        k0 = (k0 + 1) & 255;
        k1 = (k1 + 1) & 255;
        k2 = (k2 + 1) & 255;
 
        var x = s[k0] - s[k1];
        if (x < 0.0) {
          x += 1.0;
        }
        x -= s[k2];
        if (x < 0.0) {
          x += 1.0;
        }
        return s[k0] = x;
      }
 
      random.uint32 = function() {
        return random() * 0x100000000 >>> 0; // 2^32
      };
      random.fract53 = random;
      random.version = 'LFib 0.9';
      random.args = args;
 
      return random;
    } (Array.prototype.slice.call(arguments)));
  }

// LFIB4: http://baagoe.org/en/wiki/LFIB4
function LFIB4() {
  return(function(args) {
    // George Marsaglia's LFIB4,
    //http://groups.google.com/group/sci.crypt/msg/eb4ddde782b17051
    var k0 = 0,
        k1 = 58,
        k2 = 119,
        k3 = 178;
 
    var s = [];
 
    var mash = Mash();
    if (args.length === 0) {
      args = [+new Date()];
    }
    for (var j = 0; j < 256; j++) {
      s[j] = mash(' ');
      s[j] -= mash(' ') * 4.76837158203125e-7; // 2^-21
      if (s[j] < 0) {
        s[j] += 1;
      }
    }
    for (var i = 0; i < args.length; i++) {
      for (var j = 0; j < 256; j++) {
        s[j] -= mash(args[i]);
        s[j] -= mash(args[i]) * 4.76837158203125e-7; // 2^-21
        if (s[j] < 0) {
          s[j] += 1;
        }
      }
    }
    mash = null;
 
    var random = function() {
      var x;
 
      k0 = (k0 + 1) & 255;
      k1 = (k1 + 1) & 255;
      k2 = (k2 + 1) & 255;
      k3 = (k3 + 1) & 255;
 
      x = s[k0] - s[k1];
      if (x < 0) {
        x += 1;
      }
      x -= s[k2];
      if (x < 0) {
        x += 1;
      }
      x -= s[k3];
      if (x < 0) {
        x += 1;
      }
 
      return s[k0] = x;
    }
 
    random.uint32 = function() {
      return random() * 0x100000000 >>> 0; // 2^32
    };
    random.fract53 = random;
    random.version = 'LFIB4 0.9';
    random.args = args;
 
    return random;
  } (Array.prototype.slice.call(arguments)));
}

// Alea: http://baagoe.org/en/wiki/Alea
 function Alea() {
    return (function(args) {
      var s0 = 0;
      var s1 = 0;
      var s2 = 0;
      var c = 1;
 
      if (args.length == 0) {
        args = [+new Date];
      }
      var mash = Mash();
      s0 = mash(' ');
      s1 = mash(' ');
      s2 = mash(' ');
 
      for (var i = 0; i < args.length; i++) {
        s0 -= mash(args[i]);
        if (s0 < 0) {
          s0 += 1;
        }
        s1 -= mash(args[i]);
        if (s1 < 0) {
          s1 += 1;
        }
        s2 -= mash(args[i]);
        if (s2 < 0) {
          s2 += 1;
        }
      }
      mash = null;
 
      var random = function() {
        var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
        s0 = s1;
        s1 = s2;
        return s2 = t - (c = t | 0);
      };
      random.uint32 = function() {
        return random() * 0x100000000; // 2^32
      };
      random.fract53 = function() {
        return random() +
          (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
      };
      random.version = 'Alea 0.9';
      random.args = args;
      return random;
 
    } (Array.prototype.slice.call(arguments)));
  };

// Kybos: http://baagoe.org/en/wiki/Kybos
function Kybos() {
    return (function(args) {
      var s0 = 0;
      var s1 = 0;
      var s2 = 0;
      var c = 1;
      var s = [];
      var k = 0;
 
      var mash = Mash();
      var s0 = mash(' ');
      var s1 = mash(' ');
      var s2 = mash(' ');
      for (var j = 0; j < 8; j++) {
        s[j] = mash(' ');
      }
 
      if (args.length == 0) {
        args = [+new Date];
      }
      for (var i = 0; i < args.length; i++) {
        s0 -= mash(args[i]);
        if (s0 < 0) {
          s0 += 1;
        }
        s1 -= mash(args[i]);
        if (s1 < 0) {
          s1 += 1;
        }
        s2 -= mash(args[i]);
        if (s2 < 0) {
          s2 += 1;
        }
        for (var j = 0; j < 8; j++) {
          s[j] -= mash(args[i]);
          if (s[j] < 0) {
            s[j] += 1;
          }
        }
      }
 
      var random = function() {
        var a = 2091639;
        k = s[k] * 8 | 0;
        var r = s[k];
        var t = a * s0 + c * 2.3283064365386963e-10; // 2^-32
        s0 = s1;
        s1 = s2;
        s2 = t - (c = t | 0);
        s[k] -= s2;
        if (s[k] < 0) {
          s[k] += 1;
        }
        return r;
      };
      random.uint32 = function() {
        return random() * 0x100000000; // 2^32
      };
      random.fract53 = function() {
        return random() +
          (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
      };
      random.addNoise = function() {
        for (var i = arguments.length - 1; i >= 0; i--) {
          for (j = 0; j < 8; j++) {
            s[j] -= mash(arguments[i]);
            if (s[j] < 0) {
              s[j] += 1;
            }
          }
        }
      };
      random.version = 'Kybos 0.9';
      random.args = args;
      return random;
 
    } (Array.prototype.slice.call(arguments)));
  };

// test vars
var seed = 17;
var randomDeadbeef = (new DeadbeefRand(seed)).rand;
var randomMRG32k3a = MRG32k3a(seed);
var randomXorshift03 = Xorshift03(seed);
var randomKISS07 = KISS07(seed);
var randomLFib = LFib(seed);
var randomLFIB4 = LFIB4(seed);
var randomAlea = Alea(seed);
var randomKybos = Kybos(seed);
</script>

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
MRG32k3a
randomMRG32k3a();
 
pending…
Xorshift03
randomXorshift03();
pending…
KISS07
randomKISS07();
pending…
LFib
randomLFib();
pending…
LFIB4
randomLFIB4();
pending…
Alea
randomAlea();
pending…
Kybos
randomKybos();
pending…
Deadbeef
randomDeadbeef();
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment