PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Math/RandomBase.cs

#
C# | 262 lines | 133 code | 25 blank | 104 comment | 4 complexity | 47761b5ab963c6850bd4d0c0c9474e44 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Diagnostics;
  3. using NUnit.Framework;
  4. namespace Delta.Utilities.Math
  5. {
  6. /// <summary>
  7. /// This class represents the base class for all random generator
  8. /// algorithms. Based on the article "Random isn't Really Random --
  9. /// C# Random Number Generation" by Matthew Cochran. @see:
  10. /// http://www.c-sharpcorner.com/UploadFile/rmcochran/random07172006175425PM/random.aspx
  11. /// </summary>
  12. public abstract class RandomBase : Random
  13. {
  14. #region Constructors
  15. /// <summary>
  16. /// Random base
  17. /// </summary>
  18. public RandomBase()
  19. {
  20. }
  21. /// <summary>
  22. /// Create random base
  23. /// </summary>
  24. public RandomBase(int seed)
  25. : base(seed)
  26. {
  27. }
  28. #endregion
  29. #region Next (Public)
  30. /// <summary>
  31. /// Returns a nonnegative random number.
  32. /// </summary>
  33. /// <returns>
  34. /// A 32-bit signed uinteger greater than or equal to zero and less than
  35. /// <see cref="F:System.uint32.MaxValue"></see>.
  36. /// </returns>
  37. public abstract override int Next();
  38. /// <summary>
  39. /// Returns a nonnegative random number less than the specified maximum.
  40. /// </summary>
  41. /// <param name="maxValue">
  42. /// The exclusive upper bound of the random number to be generated.
  43. /// maxValue must be greater than or equal to zero.
  44. /// </param>
  45. /// <returns>
  46. /// A 32-bit signed uinteger greater than or equal to zero, and less than
  47. /// maxValue; that is, the range of return values includes zero but not
  48. /// maxValue.
  49. /// </returns>
  50. /// <exception cref="T:System.ArgumentOutOfRangeException">
  51. /// maxValue is less than zero.
  52. /// </exception>
  53. public override int Next(int maxValue)
  54. {
  55. return Next(0, maxValue);
  56. }
  57. /// <summary>
  58. /// Returns a random number within a specified range.
  59. /// </summary>
  60. /// <param name="minValue">The inclusive lower bound of the random number
  61. /// returned.
  62. /// </param>
  63. /// <param name="maxValue">The exclusive upper bound of the random number
  64. /// returned. maxValue must be greater than or equal to minValue.
  65. /// </param>
  66. /// <returns>
  67. /// A 32-bit signed uinteger greater than or equal to minValue and less
  68. /// than maxValue; that is, the range of return values includes minValue
  69. /// but not maxValue. If minValue equals maxValue, minValue is returned.
  70. /// </returns>
  71. /// <exception cref="T:System.ArgumentOutOfRangeException">
  72. /// minValue is greater than maxValue.
  73. /// </exception>
  74. public override int Next(int minValue, int maxValue)
  75. {
  76. return Convert.ToInt32(((maxValue - 1) - minValue) * Sample() + minValue);
  77. }
  78. #endregion
  79. #region NextDouble (Public)
  80. /// <summary>
  81. /// Returns a random number between 0.0 and 1.0. If you just need a float
  82. /// value instead of a double, just convert it after calling this method.
  83. /// </summary>
  84. /// <returns>
  85. /// A double-precision floating pouint number greater than or equal to 0.0,
  86. /// and less than 1.0.
  87. /// </returns>
  88. public override double NextDouble()
  89. {
  90. return Sample();
  91. }
  92. #endregion
  93. #region NextBytes (Public)
  94. /// <summary>
  95. /// Fills the elements of a specified array of bytes with random numbers.
  96. /// </summary>
  97. /// <param name="buffer">An array of bytes to contain random numbers.</param>
  98. /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
  99. public override void NextBytes(byte[] buffer)
  100. {
  101. int i, j, tmp;
  102. // fill the part of the buffer that can be covered by full Int32s
  103. for (i = 0; i < buffer.Length - 4; i += 4)
  104. {
  105. tmp = Next();
  106. buffer[i] = Convert.ToByte(tmp & 0x000000FF);
  107. buffer[i + 1] = Convert.ToByte((tmp & 0x0000FF00) >> 8);
  108. buffer[i + 2] = Convert.ToByte((tmp & 0x00FF0000) >> 16);
  109. buffer[i + 3] = Convert.ToByte((tmp & 0xFF000000) >> 24);
  110. }
  111. tmp = Next();
  112. // fill the rest of the buffer
  113. for (j = 0; j < buffer.Length % 4; j++)
  114. {
  115. buffer[i + j] =
  116. Convert.ToByte((tmp & (0x000000FF << (8 * j))) >> (8 * j));
  117. }
  118. }
  119. #endregion
  120. #region Methods (Private)
  121. #region GetBaseNextInt32
  122. /// <summary>
  123. /// Get base next int 32
  124. /// </summary>
  125. protected int GetBaseNextInt32()
  126. {
  127. return base.Next();
  128. }
  129. #endregion
  130. #region GetBaseNextUInt32
  131. /// <summary>
  132. /// Get base next u texture coordinate int 32
  133. /// </summary>
  134. protected uint GetBaseNextUInt32()
  135. {
  136. return ConvertToUInt32(base.Next());
  137. }
  138. #endregion
  139. #region GetBaseNextDouble
  140. /// <summary>
  141. /// Get base next double
  142. /// </summary>
  143. protected double GetBaseNextDouble()
  144. {
  145. return base.NextDouble();
  146. }
  147. #endregion
  148. #region Sample
  149. /// <summary>
  150. /// Returns a random number between 0.0 and 1.0.
  151. /// </summary>
  152. /// <returns>
  153. /// A double-precision floating pouint number greater than or equal to 0.0, and less than 1.0.
  154. /// </returns>
  155. protected override double Sample()
  156. {
  157. // generates a random number on [0,1) and divided by 2^31
  158. // (Int32 absolute value)
  159. return Convert.ToDouble(Next()) / 2147483648.0;
  160. }
  161. #endregion
  162. #region ConvertToUInt32
  163. /// <summary>
  164. /// Convert to u texture coordinate int 32
  165. /// </summary>
  166. /// <param name="value">Value</param>
  167. protected static UInt32 ConvertToUInt32(Int32 value)
  168. {
  169. return BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
  170. }
  171. #endregion
  172. #region ConvertToInt32
  173. /// <summary>
  174. /// Convert to int 32
  175. /// </summary>
  176. /// <param name="value">Value</param>
  177. protected static Int32 ConvertToInt32(UInt32 value)
  178. {
  179. return BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
  180. }
  181. /// <summary>
  182. /// Convert to int 32
  183. /// </summary>
  184. /// <param name="value">Value</param>
  185. protected static Int32 ConvertToInt32(UInt64 value)
  186. {
  187. return BitConverter.ToInt32(
  188. BitConverter.GetBytes(value & 0x000000007fffffff), 0);
  189. }
  190. #endregion
  191. #endregion
  192. /// <summary>
  193. /// Tests for RandomBase implementations
  194. /// </summary>
  195. internal class RandomBaseTests
  196. {
  197. #region PerformGenerator (Static)
  198. /// <summary>
  199. /// Perform generator
  200. /// </summary>
  201. [Test]
  202. private static void PerformGenerator(Random generator,
  203. Stopwatch timeCounter)
  204. {
  205. timeCounter.Reset();
  206. timeCounter.Start();
  207. for (int index = 0; index < 10000000; index++)
  208. {
  209. generator.NextDouble();
  210. }
  211. timeCounter.Stop();
  212. Console.WriteLine(
  213. "The time for the '" + generator + "' generator took '" +
  214. timeCounter.ElapsedMilliseconds + "' ms.");
  215. Console.Write("Example values are: ");
  216. for (int index = 0; index < 10; index++)
  217. {
  218. Console.Write(generator.NextDouble().ToString("0.000000 | "));
  219. }
  220. Console.WriteLine();
  221. }
  222. #endregion
  223. #region TestPerformance (LongRunning)
  224. /// <summary>
  225. /// Test performance
  226. /// </summary>
  227. [Test, Category("LongRunning")]
  228. public static void TestPerformance()
  229. {
  230. Stopwatch timeCounter = new Stopwatch();
  231. PerformGenerator(new Random(), timeCounter);
  232. PerformGenerator(new Random250Algorithm(), timeCounter);
  233. }
  234. #endregion
  235. }
  236. }
  237. }