Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. | |
| // | |
| // This fast non-cryptographic random number generator is designed for | |
| // use in Monte-Carlo algorithms. It combines a long-period xorshift | |
| // generator with a Weyl generator, and it passes all common batteries | |
| // of stasticial tests for randomness while consuming only a few nanoseconds | |
| // for each prng generated. For background on the generator, see Brent's | |
| // paper: "Some long-period random number generators using shifts and xors." | |
| // http://arxiv.org/pdf/1004.3115v1.pdf | |
| // | |
| // Usage: | |
| // | |
| // var xor4096 = require('xor4096'); | |
| // random = xor4096(1); // Seed with int32 or string. | |
| // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. | |
| // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. | |
| // | |
| // For nonzero numeric keys, this impelementation provides a sequence | |
| // identical to that by Brent's xorgens 3 implementaion in C. This | |
| // implementation also provides for initalizing the generator with | |
| // string seeds, or for saving and restoring the state of the generator. | |
| // | |
| // On Chrome, this prng benchmarks about 2.1 times slower than | |
| // Javascript's built-in Math.random(). | |
| (function(global, module, define) { | |
| function XorGen(seed) { | |
| var me = this; | |
| // Set up generator function. | |
| me.next = function() { | |
| var w = me.w, | |
| X = me.X, i = me.i, t, v; | |
| // Update Weyl generator. | |
| me.w = w = (w + 0x61c88647) | 0; | |
| // Update xor generator. | |
| v = X[(i + 34) & 127]; | |
| t = X[i = ((i + 1) & 127)]; | |
| v ^= v << 13; | |
| t ^= t << 17; | |
| v ^= v >>> 15; | |
| t ^= t >>> 12; | |
| // Update Xor generator array state. | |
| v = X[i] = v ^ t; | |
| me.i = i; | |
| // Result is the combination. | |
| return (v + (w ^ (w >>> 16))) | 0; | |
| }; | |
| function init(me, seed) { | |
| var t, v, i, j, w, X = [], limit = 128; | |
| if (seed === (seed | 0)) { | |
| // Numeric seeds initialize v, which is used to generates X. | |
| v = seed; | |
| seed = null; | |
| } else { | |
| // String seeds are mixed into v and X one character at a time. | |
| seed = seed + '\0'; | |
| v = 0; | |
| limit = Math.max(limit, seed.length); | |
| } | |
| // Initialize circular array and weyl value. | |
| for (i = 0, j = -32; j < limit; ++j) { | |
| // Put the unicode characters into the array, and shuffle them. | |
| if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); | |
| // After 32 shuffles, take v as the starting w value. | |
| if (j === 0) w = v; | |
| v ^= v << 10; | |
| v ^= v >>> 15; | |
| v ^= v << 4; | |
| v ^= v >>> 13; | |
| if (j >= 0) { | |
| w = (w + 0x61c88647) | 0; // Weyl. | |
| t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. | |
| i = (0 == t) ? i + 1 : 0; // Count zeroes. | |
| } | |
| } | |
| // We have detected all zeroes; make the key nonzero. | |
| if (i >= 128) { | |
| X[(seed && seed.length || 0) & 127] = -1; | |
| } | |
| // Run the generator 512 times to further mix the state before using it. | |
| // Factoring this as a function slows the main generator, so it is just | |
| // unrolled here. The weyl generator is not advanced while warming up. | |
| i = 127; | |
| for (j = 4 * 128; j > 0; --j) { | |
| v = X[(i + 34) & 127]; | |
| t = X[i = ((i + 1) & 127)]; | |
| v ^= v << 13; | |
| t ^= t << 17; | |
| v ^= v >>> 15; | |
| t ^= t >>> 12; | |
| X[i] = v ^ t; | |
| } | |
| // Storing state as object members is faster than using closure variables. | |
| me.w = w; | |
| me.X = X; | |
| me.i = i; | |
| } | |
| init(me, seed); | |
| } | |
| function copy(f, t) { | |
| t.i = f.i; | |
| t.w = f.w; | |
| t.X = f.X.slice(); | |
| return t; | |
| }; | |
| function impl(seed, opts) { | |
| if (seed == null) seed = +(new Date); | |
| var xg = new XorGen(seed), | |
| state = opts && opts.state, | |
| prng = function() { return (xg.next() >>> 0) / 0x100000000; }; | |
| prng.double = function() { | |
| do { | |
| var top = xg.next() >>> 11, | |
| bot = (xg.next() >>> 0) / 0x100000000, | |
| result = (top + bot) / (1 << 21); | |
| } while (result === 0); | |
| return result; | |
| }; | |
| prng.int32 = xg.next; | |
| prng.quick = prng; | |
| if (state) { | |
| if (state.X) copy(state, xg); | |
| prng.state = function() { return copy(xg, {}); } | |
| } | |
| return prng; | |
| } | |
| if (module && module.exports) { | |
| module.exports = impl; | |
| } else if (define && define.amd) { | |
| define(function() { return impl; }); | |
| } else { | |
| this.xor4096 = impl; | |
| } | |
| })( | |
| this, // window object or global | |
| (typeof module) == 'object' && module, // present in node.js | |
| (typeof define) == 'function' && define // present with an AMD loader | |
| ); |