RandomStream.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. namespace DunGen
  3. {
  4. public sealed class RandomStream
  5. {
  6. public static readonly RandomStream Global = new RandomStream();
  7. private const int maxValue = int.MaxValue;
  8. private const int seed = 161803398;
  9. private int iNext;
  10. private int iNextP;
  11. private int[] seedArray = new int[56];
  12. public RandomStream()
  13. : this(Environment.TickCount)
  14. {
  15. }
  16. public RandomStream(int Seed)
  17. {
  18. int ii;
  19. int mj, mk;
  20. int subtraction = (Seed == int.MinValue) ? int.MaxValue : Math.Abs(Seed);
  21. mj = seed - subtraction;
  22. seedArray[55] = mj;
  23. mk = 1;
  24. for (int i = 1; i < 55; i++)
  25. {
  26. ii = (21 * i) % 55;
  27. seedArray[ii] = mk;
  28. mk = mj - mk;
  29. if (mk < 0)
  30. mk += maxValue;
  31. mj = seedArray[ii];
  32. }
  33. for (int k = 1; k < 5; k++)
  34. {
  35. for (int i = 1; i < 56; i++)
  36. {
  37. seedArray[i] -= seedArray[1 + (i + 30) % 55];
  38. if (seedArray[i] < 0)
  39. seedArray[i] += maxValue;
  40. }
  41. }
  42. iNext = 0;
  43. iNextP = 21;
  44. Seed = 1;
  45. }
  46. private double Sample()
  47. {
  48. return (InternalSample() * (1.0 / maxValue));
  49. }
  50. private int InternalSample()
  51. {
  52. int retVal;
  53. int locINext = iNext;
  54. int locINextp = iNextP;
  55. if (++locINext >= 56)
  56. locINext = 1;
  57. if (++locINextp >= 56)
  58. locINextp = 1;
  59. retVal = seedArray[locINext] - seedArray[locINextp];
  60. if (retVal == maxValue)
  61. retVal--;
  62. if (retVal < 0)
  63. retVal += maxValue;
  64. seedArray[locINext] = retVal;
  65. iNext = locINext;
  66. iNextP = locINextp;
  67. return retVal;
  68. }
  69. /// <summary>
  70. /// Returns a random integer between 0 (inclusive) and int.MaxValue (exclusive)
  71. /// </summary>
  72. /// <returns>A random integer between 0 (inclusive) and int.MaxValue (exclusive)</returns>
  73. public int Next()
  74. {
  75. return InternalSample();
  76. }
  77. private double GetSampleForLargeRange()
  78. {
  79. int result = InternalSample();
  80. bool negative = (InternalSample() % 2 == 0) ? true : false;
  81. if (negative)
  82. result = -result;
  83. double d = result;
  84. d += (int.MaxValue - 1);
  85. d /= 2 * (uint)int.MaxValue - 1;
  86. return d;
  87. }
  88. /// <summary>
  89. /// Returns a random integer between minValue (inclusive) and maxValue (exclusive)
  90. /// </summary>
  91. /// <param name="minValue">Inclusive min value</param>
  92. /// <param name="maxValue">Exclusive max value</param>
  93. /// <returns>A random integer between minValue (inclusive) and maxValue (exclusive)</returns>
  94. /// <exception cref="ArgumentOutOfRangeException">minValue must be greater than maxValue</exception>
  95. public int Next(int minValue, int maxValue)
  96. {
  97. if (minValue > maxValue)
  98. throw new ArgumentOutOfRangeException("minValue");
  99. long range = (long)maxValue - minValue;
  100. if (range <= (long)Int32.MaxValue)
  101. return ((int)(Sample() * range) + minValue);
  102. else
  103. return (int)((long)(GetSampleForLargeRange() * range) + minValue);
  104. }
  105. /// <summary>
  106. /// Returns a non-negative random integer that is less than the specified maximum.
  107. /// </summary>
  108. /// <param name="maxValue">Exclusive maximum</param>
  109. /// <returns>Random integer between 0 and maxValue (exclusive)</returns>
  110. /// <exception cref="ArgumentOutOfRangeException">Max value < 0</exception>
  111. public int Next(int maxValue)
  112. {
  113. if (maxValue < 0)
  114. throw new ArgumentOutOfRangeException("maxValue");
  115. return (int)(Sample() * maxValue);
  116. }
  117. /// <summary>
  118. /// Returns a random double between 0.0 (inclusive) and 1.0 (exclusive)
  119. /// </summary>
  120. /// <returns>A random double between 0.0 (inclusive) and 1.0 (exclusive)</returns>
  121. public double NextDouble()
  122. {
  123. return Sample();
  124. }
  125. /// <summary>
  126. /// Fills an array with random bytes between 0 and 255 (inclusive)
  127. /// </summary>
  128. /// <param name="buffer">The array to fill</param>
  129. /// <exception cref="ArgumentNullException">`buffer` must not be null</exception>
  130. public void NextBytes(byte[] buffer)
  131. {
  132. if (buffer == null)
  133. throw new ArgumentNullException("buffer");
  134. for (int i = 0; i < buffer.Length; i++)
  135. buffer[i] = (byte)(InternalSample() % (byte.MaxValue + 1));
  136. }
  137. }
  138. }