xor4096.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm.
  2. //
  3. // This fast non-cryptographic random number generator is designed for
  4. // use in Monte-Carlo algorithms. It combines a long-period xorshift
  5. // generator with a Weyl generator, and it passes all common batteries
  6. // of stasticial tests for randomness while consuming only a few nanoseconds
  7. // for each prng generated. For background on the generator, see Brent's
  8. // paper: "Some long-period random number generators using shifts and xors."
  9. // http://arxiv.org/pdf/1004.3115v1.pdf
  10. //
  11. // Usage:
  12. //
  13. // var xor4096 = require('xor4096');
  14. // random = xor4096(1); // Seed with int32 or string.
  15. // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits.
  16. // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits.
  17. //
  18. // For nonzero numeric keys, this impelementation provides a sequence
  19. // identical to that by Brent's xorgens 3 implementaion in C. This
  20. // implementation also provides for initalizing the generator with
  21. // string seeds, or for saving and restoring the state of the generator.
  22. //
  23. // On Chrome, this prng benchmarks about 2.1 times slower than
  24. // Javascript's built-in Math.random().
  25. (function(global, module, define) {
  26. function XorGen(seed) {
  27. var me = this;
  28. // Set up generator function.
  29. me.next = function() {
  30. var w = me.w,
  31. X = me.X, i = me.i, t, v;
  32. // Update Weyl generator.
  33. me.w = w = (w + 0x61c88647) | 0;
  34. // Update xor generator.
  35. v = X[(i + 34) & 127];
  36. t = X[i = ((i + 1) & 127)];
  37. v ^= v << 13;
  38. t ^= t << 17;
  39. v ^= v >>> 15;
  40. t ^= t >>> 12;
  41. // Update Xor generator array state.
  42. v = X[i] = v ^ t;
  43. me.i = i;
  44. // Result is the combination.
  45. return (v + (w ^ (w >>> 16))) | 0;
  46. };
  47. function init(me, seed) {
  48. var t, v, i, j, w, X = [], limit = 128;
  49. if (seed === (seed | 0)) {
  50. // Numeric seeds initialize v, which is used to generates X.
  51. v = seed;
  52. seed = null;
  53. } else {
  54. // String seeds are mixed into v and X one character at a time.
  55. seed = seed + '\0';
  56. v = 0;
  57. limit = Math.max(limit, seed.length);
  58. }
  59. // Initialize circular array and weyl value.
  60. for (i = 0, j = -32; j < limit; ++j) {
  61. // Put the unicode characters into the array, and shuffle them.
  62. if (seed) v ^= seed.charCodeAt((j + 32) % seed.length);
  63. // After 32 shuffles, take v as the starting w value.
  64. if (j === 0) w = v;
  65. v ^= v << 10;
  66. v ^= v >>> 15;
  67. v ^= v << 4;
  68. v ^= v >>> 13;
  69. if (j >= 0) {
  70. w = (w + 0x61c88647) | 0; // Weyl.
  71. t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array.
  72. i = (0 == t) ? i + 1 : 0; // Count zeroes.
  73. }
  74. }
  75. // We have detected all zeroes; make the key nonzero.
  76. if (i >= 128) {
  77. X[(seed && seed.length || 0) & 127] = -1;
  78. }
  79. // Run the generator 512 times to further mix the state before using it.
  80. // Factoring this as a function slows the main generator, so it is just
  81. // unrolled here. The weyl generator is not advanced while warming up.
  82. i = 127;
  83. for (j = 4 * 128; j > 0; --j) {
  84. v = X[(i + 34) & 127];
  85. t = X[i = ((i + 1) & 127)];
  86. v ^= v << 13;
  87. t ^= t << 17;
  88. v ^= v >>> 15;
  89. t ^= t >>> 12;
  90. X[i] = v ^ t;
  91. }
  92. // Storing state as object members is faster than using closure variables.
  93. me.w = w;
  94. me.X = X;
  95. me.i = i;
  96. }
  97. init(me, seed);
  98. }
  99. function copy(f, t) {
  100. t.i = f.i;
  101. t.w = f.w;
  102. t.X = f.X.slice();
  103. return t;
  104. };
  105. function impl(seed, opts) {
  106. if (seed == null) seed = +(new Date);
  107. var xg = new XorGen(seed),
  108. state = opts && opts.state,
  109. prng = function() { return (xg.next() >>> 0) / 0x100000000; };
  110. prng.double = function() {
  111. do {
  112. var top = xg.next() >>> 11,
  113. bot = (xg.next() >>> 0) / 0x100000000,
  114. result = (top + bot) / (1 << 21);
  115. } while (result === 0);
  116. return result;
  117. };
  118. prng.int32 = xg.next;
  119. prng.quick = prng;
  120. if (state) {
  121. if (state.X) copy(state, xg);
  122. prng.state = function() { return copy(xg, {}); }
  123. }
  124. return prng;
  125. }
  126. if (module && module.exports) {
  127. module.exports = impl;
  128. } else if (define && define.amd) {
  129. define(function() { return impl; });
  130. } else {
  131. this.xor4096 = impl;
  132. }
  133. })(
  134. this, // window object or global
  135. (typeof module) == 'object' && module, // present in node.js
  136. (typeof define) == 'function' && define // present with an AMD loader
  137. );