You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
4.7KB

  1. // Copyright 2014 Thom Chiovoloni, released under the MIT license.
  2. /// A random number generator based on the basic implementation of the PCG algorithm,
  3. /// as described here: http://www.pcg-random.org/
  4. var PcgRandom = (function() {
  5. 'use strict';
  6. var defaultIncHi = 0x14057b7e;
  7. var defaultIncLo = 0xf767814f;
  8. /// Construct a random number generator.
  9. function PcgRandom(seedHi, seedLo, incHi, incLo) {
  10. this.setSeed(seedHi, seedLo, incHi, incLo)
  11. }
  12. /// Set the seed and incrementer.
  13. PcgRandom.prototype.setSeed = function(seedHi, seedLo, incHi, incLo) {
  14. if (seedLo == null && seedHi == null) {
  15. seedLo = (Math.random() * 0xffffffff) >>> 0;
  16. seedHi = 0;
  17. }
  18. else if (seedLo == null) {
  19. seedLo = seedHi;
  20. seedHi = 0;
  21. }
  22. if (incLo == null && incHi == null) {
  23. incLo = this.state_ ? this.state_[3] : defaultIncLo;
  24. incHi = this.state_ ? this.state_[2] : defaultIncHi;
  25. }
  26. else if (incLo == null) {
  27. incLo = incHi;
  28. incHi = 0;
  29. }
  30. this.state_ = new Int32Array([ 0, 0, incHi >>> 0, (incLo|1) >>> 0 ]);
  31. this.next_();
  32. add64_(this.state_, this.state_[0], this.state_[1], seedHi>>>0, seedLo>>>0);
  33. this.next_();
  34. return this;
  35. };
  36. /// Return a copy of the internal state of this random number generator as a JavaScript Array.
  37. PcgRandom.prototype.getState = function() {
  38. return [this.state_[0], this.state_[1], this.state_[2], this.state_[3]];
  39. };
  40. /// Set the state of the random number generator.
  41. PcgRandom.prototype.setState = function(state) {
  42. this.state_[0] = state[0];
  43. this.state_[1] = state[1];
  44. this.state_[2] = state[2];
  45. this.state_[3] = state[3]|1;
  46. };
  47. // shim for Math.imul.
  48. var imul = Math.imul;
  49. if (!imul) {
  50. imul = function(a, b) {
  51. var ah = (a >>> 16) & 0xffff, al = a & 0xffff;
  52. var bh = (b >>> 16) & 0xffff, bl = b & 0xffff;
  53. return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) | 0);
  54. };
  55. }
  56. // multiply two 64 bit numbers (given in parts), and store the result in `out`.
  57. function mul64_(out, aHi, aLo, bHi, bLo) {
  58. var c1 = (aLo >>> 16) * (bLo & 0xffff) >>> 0;
  59. var c0 = (aLo & 0xffff) * (bLo >>> 16) >>> 0;
  60. var lo = ((aLo & 0xffff) * (bLo & 0xffff)) >>> 0;
  61. var hi = ((aLo >>> 16) * (bLo >>> 16)) + ((c0 >>> 16) + (c1 >>> 16)) >>> 0;
  62. c0 = (c0 << 16) >>> 0;
  63. lo = (lo + c0) >>> 0;
  64. if ((lo >>> 0) < (c0 >>> 0)) {
  65. hi = (hi + 1) >>> 0;
  66. }
  67. c1 = (c1 << 16) >>> 0;
  68. lo = (lo + c1) >>> 0;
  69. if ((lo >>> 0) < (c1 >>> 0)) {
  70. hi = (hi + 1) >>> 0;
  71. }
  72. hi = (hi + imul(aLo, bHi)) >>> 0;
  73. hi = (hi + imul(aHi, bLo)) >>> 0;
  74. out[0] = hi;
  75. out[1] = lo;
  76. }
  77. // add two 64 bit numbers (given in parts), and store the result in `out`.
  78. function add64_(out, aHi, aLo, bHi, bLo) {
  79. var hi = (aHi + bHi) >>> 0;
  80. var lo = (aLo + bLo) >>> 0;
  81. if ((lo >>> 0) < (aLo >>> 0)) {
  82. hi = (hi + 1) | 0;
  83. }
  84. out[0] = hi;
  85. out[1] = lo;
  86. }
  87. var MUL_HI = 0x5851f42d >>> 0;
  88. var MUL_LO = 0x4c957f2d >>> 0;
  89. /// Generate a random 32 bit integer. This uses the PCG algorithm, described
  90. /// here: http://www.pcg-random.org/
  91. PcgRandom.prototype.next_ = function() {
  92. // save current state (what we'll use for this number)
  93. var oldHi = this.state_[0] >>> 0;
  94. var oldLo = this.state_[1] >>> 0;
  95. // churn LCG.
  96. mul64_(this.state_, oldHi, oldLo, MUL_HI, MUL_LO);
  97. add64_(this.state_, this.state_[0], this.state_[1], this.state_[2], this.state_[3]);
  98. // get least sig. 32 bits of ((oldstate >> 18) ^ oldstate) >> 27
  99. var xsHi = oldHi >>> 18;
  100. var xsLo = ((oldLo >>> 18) | (oldHi << 14)) >>> 0;
  101. xsHi = (xsHi ^ oldHi) >>> 0;
  102. xsLo = (xsLo ^ oldLo) >>> 0;
  103. var xorshifted = ((xsLo >>> 27) | (xsHi << 5)) >>> 0;
  104. // rotate xorshifted right a random amount, based on the most sig. 5 bits
  105. // bits of the old state.
  106. var rot = oldHi >>> 27;
  107. var rot2 = ((-rot >>> 0) & 31) >>> 0;
  108. return ((xorshifted >>> rot) | (xorshifted << rot2)) >>> 0;
  109. };
  110. /// Get a uniformly distributed 32 bit integer between [0, max).
  111. PcgRandom.prototype.integer = function(max) {
  112. if (!max) {
  113. return this.next_();
  114. }
  115. max = max >>> 0;
  116. if ((max & (max - 1)) === 0) {
  117. return this.next_() & (max - 1); // fast path for power of 2
  118. }
  119. var num = 0;
  120. var skew = ((-max >>> 0) % max) >>> 0;
  121. for (num = this.next_(); num < skew; num = this.next_()) {
  122. // this loop will rarely execute more than twice,
  123. // and is intentionally empty
  124. }
  125. return num % max;
  126. };
  127. var BIT_53 = 9007199254740992.0;
  128. var BIT_27 = 134217728.0;
  129. /// Get a uniformly distributed IEEE-754 double between 0.0 and 1.0, with
  130. /// 53 bits of precision (every bit of the mantissa is randomized).
  131. PcgRandom.prototype.number = function() {
  132. var hi = (this.next_() & 0x03ffffff) * 1.0;
  133. var lo = (this.next_() & 0x07ffffff) * 1.0;
  134. return ((hi * BIT_27) + lo) / BIT_53;
  135. };
  136. return PcgRandom;
  137. }());
  138. if (typeof module !== 'undefined' && module.exports) {
  139. module.exports = PcgRandom;
  140. }