PageRenderTime 52ms CodeModel.GetById 39ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Math/RandomBase.cs

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