MersenneTwister.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. using System.Collections;
  2. using System;
  3. namespace NPack
  4. {
  5. /// <summary>
  6. /// Generates pseudo-random numbers using the Mersenne Twister algorithm.
  7. /// </summary>
  8. /// <remarks>
  9. /// See <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
  10. /// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html%3C/a> for details
  11. /// on the algorithm.
  12. /// </remarks>
  13. public class MersenneTwister : Random
  14. {
  15. /// <summary>
  16. /// Creates a new pseudo-random number generator with a given seed.
  17. /// </summary>
  18. /// <param name="seed">A value to use as a seed.</param>
  19. public MersenneTwister(Int32 seed)
  20. {
  21. init((UInt32)seed);
  22. }
  23. /// <summary>
  24. /// Creates a new pseudo-random number generator with a default seed.
  25. /// </summary>
  26. /// <remarks>
  27. /// <c>new <see cref="System.Random"/>().<see cref="Random.Next()"/></c>
  28. /// is used for the seed.
  29. /// </remarks>
  30. public MersenneTwister()
  31. : this(new Random().Next()) /* a default initial seed is used */
  32. { }
  33. /// <summary>
  34. /// Creates a pseudo-random number generator initialized with the given array.
  35. /// </summary>
  36. /// <param name="initKey">The array for initializing keys.</param>
  37. public MersenneTwister(Int32[] initKey)
  38. {
  39. if (initKey == null)
  40. {
  41. throw new ArgumentNullException("initKey");
  42. }
  43. UInt32[] initArray = new UInt32[initKey.Length];
  44. for (int i = 0; i < initKey.Length; ++i)
  45. {
  46. initArray[i] = (UInt32)initKey[i];
  47. }
  48. init(initArray);
  49. }
  50. public MersenneTwister(Random rnd)
  51. {
  52. // TODO: Complete member initialization
  53. this.rnd = rnd;
  54. }
  55. /// <summary>
  56. /// Returns the next pseudo-random <see cref="UInt32"/>.
  57. /// </summary>
  58. /// <returns>A pseudo-random <see cref="UInt32"/> value.</returns>
  59. //[CLSCompliant(false)]
  60. public virtual UInt32 NextUInt32()
  61. {
  62. return GenerateUInt32();
  63. }
  64. /// <summary>
  65. /// Returns the next pseudo-random <see cref="UInt32"/>
  66. /// up to <paramref name="maxValue"/>.
  67. /// </summary>
  68. /// <param name="maxValue">
  69. /// The maximum value of the pseudo-random number to create.
  70. /// </param>
  71. /// <returns>
  72. /// A pseudo-random <see cref="UInt32"/> value which is at most <paramref name="maxValue"/>.
  73. /// </returns>
  74. //[CLSCompliant(false)]
  75. public virtual UInt32 NextUInt32(UInt32 maxValue)
  76. {
  77. return (UInt32)(GenerateUInt32() / ((Double)UInt32.MaxValue / maxValue));
  78. }
  79. /// <summary>
  80. /// Returns the next pseudo-random <see cref="UInt32"/> at least
  81. /// <paramref name="minValue"/> and up to <paramref name="maxValue"/>.
  82. /// </summary>
  83. /// <param name="minValue">The minimum value of the pseudo-random number to create.</param>
  84. /// <param name="maxValue">The maximum value of the pseudo-random number to create.</param>
  85. /// <returns>
  86. /// A pseudo-random <see cref="UInt32"/> value which is at least
  87. /// <paramref name="minValue"/> and at most <paramref name="maxValue"/>.
  88. /// </returns>
  89. /// <exception cref="ArgumentOutOfRangeException">
  90. /// If <c><paramref name="minValue"/> &gt;= <paramref name="maxValue"/></c>.
  91. /// </exception>
  92. //[CLSCompliant(false)]
  93. public virtual UInt32 NextUInt32(UInt32 minValue, UInt32 maxValue) /* throws ArgumentOutOfRangeException */
  94. {
  95. if (minValue >= maxValue)
  96. {
  97. throw new ArgumentOutOfRangeException();
  98. }
  99. return (UInt32)(GenerateUInt32() / ((Double)UInt32.MaxValue / (maxValue - minValue)) + minValue);
  100. }
  101. /// <summary>
  102. /// Returns the next pseudo-random <see cref="Int32"/>.
  103. /// </summary>
  104. /// <returns>A pseudo-random <see cref="Int32"/> value.</returns>
  105. public override Int32 Next()
  106. {
  107. return Next(Int32.MaxValue);
  108. }
  109. /// <summary>
  110. /// Returns the next pseudo-random <see cref="Int32"/> up to <paramref name="maxValue"/>.
  111. /// </summary>
  112. /// <param name="maxValue">The maximum value of the pseudo-random number to create.</param>
  113. /// <returns>
  114. /// A pseudo-random <see cref="Int32"/> value which is at most <paramref name="maxValue"/>.
  115. /// </returns>
  116. /// <exception cref="ArgumentOutOfRangeException">
  117. /// When <paramref name="maxValue"/> &lt; 0.
  118. /// </exception>
  119. public override Int32 Next(Int32 maxValue)
  120. {
  121. if (maxValue <= 1)
  122. {
  123. if (maxValue < 0)
  124. {
  125. throw new ArgumentOutOfRangeException();
  126. }
  127. return 0;
  128. }
  129. return (Int32)(NextDouble() * maxValue);
  130. }
  131. /// <summary>
  132. /// Returns the next pseudo-random <see cref="Int32"/>
  133. /// at least <paramref name="minValue"/>
  134. /// and up to <paramref name="maxValue"/>.
  135. /// </summary>
  136. /// <param name="minValue">The minimum value of the pseudo-random number to create.</param>
  137. /// <param name="maxValue">The maximum value of the pseudo-random number to create.</param>
  138. /// <returns>A pseudo-random Int32 value which is at least <paramref name="minValue"/> and at
  139. /// most <paramref name="maxValue"/>.</returns>
  140. /// <exception cref="ArgumentOutOfRangeException">
  141. /// If <c><paramref name="minValue"/> &gt;= <paramref name="maxValue"/></c>.
  142. /// </exception>
  143. public override Int32 Next(Int32 minValue, Int32 maxValue)
  144. {
  145. if (maxValue <= minValue)
  146. {
  147. throw new ArgumentOutOfRangeException();
  148. }
  149. if (maxValue == minValue)
  150. {
  151. return minValue;
  152. }
  153. return Next(maxValue - minValue) + minValue;
  154. }
  155. /// <summary>
  156. /// Fills a buffer with pseudo-random bytes.
  157. /// </summary>
  158. /// <param name="buffer">The buffer to fill.</param>
  159. /// <exception cref="ArgumentNullException">
  160. /// If <c><paramref name="buffer"/> == <see langword="null"/></c>.
  161. /// </exception>
  162. public override void NextBytes(Byte[] buffer)
  163. {
  164. // [codekaizen: corrected this to check null before checking length.]
  165. if (buffer == null)
  166. {
  167. throw new ArgumentNullException();
  168. }
  169. Int32 bufLen = buffer.Length;
  170. for (Int32 idx = 0; idx < bufLen; ++idx)
  171. {
  172. buffer[idx] = (Byte)Next(256);
  173. }
  174. }
  175. /// <summary>
  176. /// Returns the next pseudo-random <see cref="Double"/> value.
  177. /// </summary>
  178. /// <returns>A pseudo-random double floating point value.</returns>
  179. /// <remarks>
  180. /// <para>
  181. /// There are two common ways to create a double floating point using MT19937:
  182. /// using <see cref="GenerateUInt32"/> and dividing by 0xFFFFFFFF + 1,
  183. /// or else generating two double words and shifting the first by 26 bits and
  184. /// adding the second.
  185. /// </para>
  186. /// <para>
  187. /// In a newer measurement of the randomness of MT19937 published in the
  188. /// journal "Monte Carlo Methods and Applications, Vol. 12, No. 5-6, pp. 385 –§C 393 (2006)"
  189. /// entitled "A Repetition Test for Pseudo-Random Number Generators",
  190. /// it was found that the 32-bit version of generating a double fails at the 95%
  191. /// confidence level when measuring for expected repetitions of a particular
  192. /// number in a sequence of numbers generated by the algorithm.
  193. /// </para>
  194. /// <para>
  195. /// Due to this, the 53-bit method is implemented here and the 32-bit method
  196. /// of generating a double is not. If, for some reason,
  197. /// the 32-bit method is needed, it can be generated by the following:
  198. /// <code>
  199. /// (Double)NextUInt32() / ((UInt64)UInt32.MaxValue + 1);
  200. /// </code>
  201. /// </para>
  202. /// </remarks>
  203. public override Double NextDouble()
  204. {
  205. return compute53BitRandom(0, InverseOnePlus53BitsOf1s);
  206. }
  207. /// <summary>
  208. /// Returns a pseudo-random number greater than or equal to zero, and
  209. /// either strictly less than one, or less than or equal to one,
  210. /// depending on the value of the given parameter.
  211. /// </summary>
  212. /// <param name="includeOne">
  213. /// If <see langword="true"/>, the pseudo-random number returned will be
  214. /// less than or equal to one; otherwise, the pseudo-random number returned will
  215. /// be strictly less than one.
  216. /// </param>
  217. /// <returns>
  218. /// If <paramref name="includeOne"/> is <see langword="true"/>,
  219. /// this method returns a double-precision pseudo-random number greater than
  220. /// or equal to zero, and less than or equal to one.
  221. /// If <paramref name="includeOne"/> is <see langword="false"/>, this method
  222. /// returns a double-precision pseudo-random number greater than or equal to zero and
  223. /// strictly less than one.
  224. /// </returns>
  225. public Double NextDouble(Boolean includeOne)
  226. {
  227. return includeOne ? compute53BitRandom(0, Inverse53BitsOf1s) : NextDouble();
  228. }
  229. /// <summary>
  230. /// Returns a pseudo-random number greater than 0.0 and less than 1.0.
  231. /// </summary>
  232. /// <returns>A pseudo-random number greater than 0.0 and less than 1.0.</returns>
  233. public Double NextDoublePositive()
  234. {
  235. return compute53BitRandom(0.5, Inverse53BitsOf1s);
  236. }
  237. /// <summary>
  238. /// Returns a pseudo-random number between 0.0 and 1.0.
  239. /// </summary>
  240. /// <returns>
  241. /// A single-precision floating point number greater than or equal to 0.0,
  242. /// and less than 1.0.
  243. /// </returns>
  244. public Single NextSingle()
  245. {
  246. return (Single)NextDouble();
  247. }
  248. /// <summary>
  249. /// Returns a pseudo-random number greater than or equal to zero, and either strictly
  250. /// less than one, or less than or equal to one, depending on the value of the
  251. /// given boolean parameter.
  252. /// </summary>
  253. /// <param name="includeOne">
  254. /// If <see langword="true"/>, the pseudo-random number returned will be
  255. /// less than or equal to one; otherwise, the pseudo-random number returned will
  256. /// be strictly less than one.
  257. /// </param>
  258. /// <returns>
  259. /// If <paramref name="includeOne"/> is <see langword="true"/>, this method returns a
  260. /// single-precision pseudo-random number greater than or equal to zero, and less
  261. /// than or equal to one. If <paramref name="includeOne"/> is <see langword="false"/>,
  262. /// this method returns a single-precision pseudo-random number greater than or equal to zero and
  263. /// strictly less than one.
  264. /// </returns>
  265. public Single NextSingle(Boolean includeOne)
  266. {
  267. return (Single)NextDouble(includeOne);
  268. }
  269. /// <summary>
  270. /// Returns a pseudo-random number greater than 0.0 and less than 1.0.
  271. /// </summary>
  272. /// <returns>A pseudo-random number greater than 0.0 and less than 1.0.</returns>
  273. public Single NextSinglePositive()
  274. {
  275. return (Single)NextDoublePositive();
  276. }
  277. /// <summary>
  278. /// Generates a new pseudo-random <see cref="UInt32"/>.
  279. /// </summary>
  280. /// <returns>A pseudo-random <see cref="UInt32"/>.</returns>
  281. //[CLSCompliant(false)]
  282. protected UInt32 GenerateUInt32()
  283. {
  284. UInt32 y;
  285. /* _mag01[x] = x * MatrixA for x=0,1 */
  286. if (_mti >= N) /* generate N words at one time */
  287. {
  288. Int16 kk = 0;
  289. for (; kk < N - M; ++kk)
  290. {
  291. y = (_mt[kk] & UpperMask) | (_mt[kk + 1] & LowerMask);
  292. _mt[kk] = _mt[kk + M] ^ (y >> 1) ^ _mag01[y & 0x1];
  293. }
  294. for (; kk < N - 1; ++kk)
  295. {
  296. y = (_mt[kk] & UpperMask) | (_mt[kk + 1] & LowerMask);
  297. _mt[kk] = _mt[kk + (M - N)] ^ (y >> 1) ^ _mag01[y & 0x1];
  298. }
  299. y = (_mt[N - 1] & UpperMask) | (_mt[0] & LowerMask);
  300. _mt[N - 1] = _mt[M - 1] ^ (y >> 1) ^ _mag01[y & 0x1];
  301. _mti = 0;
  302. }
  303. y = _mt[_mti++];
  304. y ^= temperingShiftU(y);
  305. y ^= temperingShiftS(y) & TemperingMaskB;
  306. y ^= temperingShiftT(y) & TemperingMaskC;
  307. y ^= temperingShiftL(y);
  308. return y;
  309. }
  310. /* Period parameters */
  311. private const Int32 N = 624;
  312. private const Int32 M = 397;
  313. private const UInt32 MatrixA = 0x9908b0df; /* constant vector a */
  314. private const UInt32 UpperMask = 0x80000000; /* most significant w-r bits */
  315. private const UInt32 LowerMask = 0x7fffffff; /* least significant r bits */
  316. /* Tempering parameters */
  317. private const UInt32 TemperingMaskB = 0x9d2c5680;
  318. private const UInt32 TemperingMaskC = 0xefc60000;
  319. private static UInt32 temperingShiftU(UInt32 y)
  320. {
  321. return (y >> 11);
  322. }
  323. private static UInt32 temperingShiftS(UInt32 y)
  324. {
  325. return (y << 7);
  326. }
  327. private static UInt32 temperingShiftT(UInt32 y)
  328. {
  329. return (y << 15);
  330. }
  331. private static UInt32 temperingShiftL(UInt32 y)
  332. {
  333. return (y >> 18);
  334. }
  335. private readonly UInt32[] _mt = new UInt32[N]; /* the array for the state vector */
  336. private Int16 _mti;
  337. private static readonly UInt32[] _mag01 = { 0x0, MatrixA };
  338. private void init(UInt32 seed)
  339. {
  340. _mt[0] = seed & 0xffffffffU;
  341. for (_mti = 1; _mti < N; _mti++)
  342. {
  343. _mt[_mti] = (uint)(1812433253U * (_mt[_mti - 1] ^ (_mt[_mti - 1] >> 30)) + _mti);
  344. // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
  345. // In the previous versions, MSBs of the seed affect
  346. // only MSBs of the array _mt[].
  347. // 2002/01/09 modified by Makoto Matsumoto
  348. _mt[_mti] &= 0xffffffffU;
  349. // for >32 bit machines
  350. }
  351. }
  352. private void init(UInt32[] key)
  353. {
  354. Int32 i, j, k;
  355. init(19650218U);
  356. Int32 keyLength = key.Length;
  357. i = 1; j = 0;
  358. k = (N > keyLength ? N : keyLength);
  359. for (; k > 0; k--)
  360. {
  361. _mt[i] = (uint)((_mt[i] ^ ((_mt[i - 1] ^ (_mt[i - 1] >> 30)) * 1664525U)) + key[j] + j); /* non linear */
  362. _mt[i] &= 0xffffffffU; // for WORDSIZE > 32 machines
  363. i++; j++;
  364. if (i >= N) { _mt[0] = _mt[N - 1]; i = 1; }
  365. if (j >= keyLength) j = 0;
  366. }
  367. for (k = N - 1; k > 0; k--)
  368. {
  369. _mt[i] = (uint)((_mt[i] ^ ((_mt[i - 1] ^ (_mt[i - 1] >> 30)) * 1566083941U)) - i); /* non linear */
  370. _mt[i] &= 0xffffffffU; // for WORDSIZE > 32 machines
  371. i++;
  372. if (i < N)
  373. {
  374. continue;
  375. }
  376. _mt[0] = _mt[N - 1]; i = 1;
  377. }
  378. _mt[0] = 0x80000000U; // MSB is 1; assuring non-zero initial array
  379. }
  380. // 9007199254740991.0 is the maximum double value which the 53 significand
  381. // can hold when the exponent is 0.
  382. private const Double FiftyThreeBitsOf1s = 9007199254740991.0;
  383. // Multiply by inverse to (vainly?) try to avoid a division.
  384. private const Double Inverse53BitsOf1s = 1.0 / FiftyThreeBitsOf1s;
  385. private const Double OnePlus53BitsOf1s = FiftyThreeBitsOf1s + 1;
  386. private const Double InverseOnePlus53BitsOf1s = 1.0 / OnePlus53BitsOf1s;
  387. private Random rnd;
  388. private Double compute53BitRandom(Double translate, Double scale)
  389. {
  390. // get 27 pseudo-random bits
  391. UInt64 a = (UInt64)GenerateUInt32() >> 5;
  392. // get 26 pseudo-random bits
  393. UInt64 b = (UInt64)GenerateUInt32() >> 6;
  394. // shift the 27 pseudo-random bits (a) over by 26 bits (* 67108864.0) and
  395. // add another pseudo-random 26 bits (+ b).
  396. return ((a * 67108864.0 + b) + translate) * scale;
  397. }
  398. }
  399. }