simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

tychei.js (2525B)


      1 // A Javascript implementaion of the "Tyche-i" prng algorithm by
      2 // Samuel Neves and Filipe Araujo.
      3 // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf
      4 
      5 (function(global, module, define) {
      6 
      7 function XorGen(seed) {
      8   var me = this, strseed = '';
      9 
     10   // Set up generator function.
     11   me.next = function() {
     12     var b = me.b, c = me.c, d = me.d, a = me.a;
     13     b = (b << 25) ^ (b >>> 7) ^ c;
     14     c = (c - d) | 0;
     15     d = (d << 24) ^ (d >>> 8) ^ a;
     16     a = (a - b) | 0;
     17     me.b = b = (b << 20) ^ (b >>> 12) ^ c;
     18     me.c = c = (c - d) | 0;
     19     me.d = (d << 16) ^ (c >>> 16) ^ a;
     20     return me.a = (a - b) | 0;
     21   };
     22 
     23   /* The following is non-inverted tyche, which has better internal
     24    * bit diffusion, but which is about 25% slower than tyche-i in JS.
     25   me.next = function() {
     26     var a = me.a, b = me.b, c = me.c, d = me.d;
     27     a = (me.a + me.b | 0) >>> 0;
     28     d = me.d ^ a; d = d << 16 ^ d >>> 16;
     29     c = me.c + d | 0;
     30     b = me.b ^ c; b = b << 12 ^ d >>> 20;
     31     me.a = a = a + b | 0;
     32     d = d ^ a; me.d = d = d << 8 ^ d >>> 24;
     33     me.c = c = c + d | 0;
     34     b = b ^ c;
     35     return me.b = (b << 7 ^ b >>> 25);
     36   }
     37   */
     38 
     39   me.a = 0;
     40   me.b = 0;
     41   me.c = 2654435769 | 0;
     42   me.d = 1367130551;
     43 
     44   if (seed === Math.floor(seed)) {
     45     // Integer seed.
     46     me.a = (seed / 0x100000000) | 0;
     47     me.b = seed | 0;
     48   } else {
     49     // String seed.
     50     strseed += seed;
     51   }
     52 
     53   // Mix in string seed, then discard an initial batch of 64 values.
     54   for (var k = 0; k < strseed.length + 20; k++) {
     55     me.b ^= strseed.charCodeAt(k) | 0;
     56     me.next();
     57   }
     58 }
     59 
     60 function copy(f, t) {
     61   t.a = f.a;
     62   t.b = f.b;
     63   t.c = f.c;
     64   t.d = f.d;
     65   return t;
     66 };
     67 
     68 function impl(seed, opts) {
     69   var xg = new XorGen(seed),
     70       state = opts && opts.state,
     71       prng = function() { return (xg.next() >>> 0) / 0x100000000; };
     72   prng.double = function() {
     73     do {
     74       var top = xg.next() >>> 11,
     75           bot = (xg.next() >>> 0) / 0x100000000,
     76           result = (top + bot) / (1 << 21);
     77     } while (result === 0);
     78     return result;
     79   };
     80   prng.int32 = xg.next;
     81   prng.quick = prng;
     82   if (state) {
     83     if (typeof(state) == 'object') copy(state, xg);
     84     prng.state = function() { return copy(xg, {}); }
     85   }
     86   return prng;
     87 }
     88 
     89 if (module && module.exports) {
     90   module.exports = impl;
     91 } else if (define && define.amd) {
     92   define(function() { return impl; });
     93 } else {
     94   this.tychei = impl;
     95 }
     96 
     97 })(
     98   this,
     99   (typeof module) == 'object' && module,    // present in node.js
    100   (typeof define) == 'function' && define   // present with an AMD loader
    101 );
    102 
    103