/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
- using System;
- using System.Diagnostics;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Math
- {
- /// <summary>
- /// This class represents the base class for all random generator
- /// algorithms. Based on the article "Random isn't Really Random --
- /// C# Random Number Generation" by Matthew Cochran. @see:
- /// http://www.c-sharpcorner.com/UploadFile/rmcochran/random07172006175425PM/random.aspx
- /// </summary>
- public abstract class RandomBase : Random
- {
- #region Constructors
- /// <summary>
- /// Random base
- /// </summary>
- public RandomBase()
- {
- }
-
- /// <summary>
- /// Create random base
- /// </summary>
- public RandomBase(int seed)
- : base(seed)
- {
- }
- #endregion
-
- #region Next (Public)
- /// <summary>
- /// Returns a nonnegative random number.
- /// </summary>
- /// <returns>
- /// A 32-bit signed uinteger greater than or equal to zero and less than
- /// <see cref="F:System.uint32.MaxValue"></see>.
- /// </returns>
- public abstract override int Next();
-
- /// <summary>
- /// Returns a nonnegative random number less than the specified maximum.
- /// </summary>
- /// <param name="maxValue">
- /// The exclusive upper bound of the random number to be generated.
- /// maxValue must be greater than or equal to zero.
- /// </param>
- /// <returns>
- /// A 32-bit signed uinteger greater than or equal to zero, and less than
- /// maxValue; that is, the range of return values includes zero but not
- /// maxValue.
- /// </returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException">
- /// maxValue is less than zero.
- /// </exception>
- public override int Next(int maxValue)
- {
- return Next(0, maxValue);
- }
-
- /// <summary>
- /// Returns a random number within a specified range.
- /// </summary>
- /// <param name="minValue">The inclusive lower bound of the random number
- /// returned.
- /// </param>
- /// <param name="maxValue">The exclusive upper bound of the random number
- /// returned. maxValue must be greater than or equal to minValue.
- /// </param>
- /// <returns>
- /// A 32-bit signed uinteger greater than or equal to minValue and less
- /// than maxValue; that is, the range of return values includes minValue
- /// but not maxValue. If minValue equals maxValue, minValue is returned.
- /// </returns>
- /// <exception cref="T:System.ArgumentOutOfRangeException">
- /// minValue is greater than maxValue.
- /// </exception>
- public override int Next(int minValue, int maxValue)
- {
- return Convert.ToInt32(((maxValue - 1) - minValue) * Sample() + minValue);
- }
- #endregion
-
- #region NextDouble (Public)
- /// <summary>
- /// Returns a random number between 0.0 and 1.0. If you just need a float
- /// value instead of a double, just convert it after calling this method.
- /// </summary>
- /// <returns>
- /// A double-precision floating pouint number greater than or equal to 0.0,
- /// and less than 1.0.
- /// </returns>
- public override double NextDouble()
- {
- return Sample();
- }
- #endregion
-
- #region NextBytes (Public)
- /// <summary>
- /// Fills the elements of a specified array of bytes with random numbers.
- /// </summary>
- /// <param name="buffer">An array of bytes to contain random numbers.</param>
- /// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
- public override void NextBytes(byte[] buffer)
- {
- int i, j, tmp;
-
- // fill the part of the buffer that can be covered by full Int32s
- for (i = 0; i < buffer.Length - 4; i += 4)
- {
- tmp = Next();
-
- buffer[i] = Convert.ToByte(tmp & 0x000000FF);
- buffer[i + 1] = Convert.ToByte((tmp & 0x0000FF00) >> 8);
- buffer[i + 2] = Convert.ToByte((tmp & 0x00FF0000) >> 16);
- buffer[i + 3] = Convert.ToByte((tmp & 0xFF000000) >> 24);
- }
-
- tmp = Next();
-
- // fill the rest of the buffer
- for (j = 0; j < buffer.Length % 4; j++)
- {
- buffer[i + j] =
- Convert.ToByte((tmp & (0x000000FF << (8 * j))) >> (8 * j));
- }
- }
- #endregion
-
- #region Methods (Private)
-
- #region GetBaseNextInt32
- /// <summary>
- /// Get base next int 32
- /// </summary>
- protected int GetBaseNextInt32()
- {
- return base.Next();
- }
- #endregion
-
- #region GetBaseNextUInt32
- /// <summary>
- /// Get base next u texture coordinate int 32
- /// </summary>
- protected uint GetBaseNextUInt32()
- {
- return ConvertToUInt32(base.Next());
- }
- #endregion
-
- #region GetBaseNextDouble
- /// <summary>
- /// Get base next double
- /// </summary>
- protected double GetBaseNextDouble()
- {
- return base.NextDouble();
- }
- #endregion
-
- #region Sample
- /// <summary>
- /// Returns a random number between 0.0 and 1.0.
- /// </summary>
- /// <returns>
- /// A double-precision floating pouint number greater than or equal to 0.0, and less than 1.0.
- /// </returns>
- protected override double Sample()
- {
- // generates a random number on [0,1) and divided by 2^31
- // (Int32 absolute value)
- return Convert.ToDouble(Next()) / 2147483648.0;
- }
- #endregion
-
- #region ConvertToUInt32
- /// <summary>
- /// Convert to u texture coordinate int 32
- /// </summary>
- /// <param name="value">Value</param>
- protected static UInt32 ConvertToUInt32(Int32 value)
- {
- return BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
- }
- #endregion
-
- #region ConvertToInt32
- /// <summary>
- /// Convert to int 32
- /// </summary>
- /// <param name="value">Value</param>
- protected static Int32 ConvertToInt32(UInt32 value)
- {
- return BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
- }
-
- /// <summary>
- /// Convert to int 32
- /// </summary>
- /// <param name="value">Value</param>
- protected static Int32 ConvertToInt32(UInt64 value)
- {
- return BitConverter.ToInt32(
- BitConverter.GetBytes(value & 0x000000007fffffff), 0);
- }
- #endregion
-
- #endregion
-
- /// <summary>
- /// Tests for RandomBase implementations
- /// </summary>
- internal class RandomBaseTests
- {
- #region PerformGenerator (Static)
- /// <summary>
- /// Perform generator
- /// </summary>
- [Test]
- private static void PerformGenerator(Random generator,
- Stopwatch timeCounter)
- {
- timeCounter.Reset();
- timeCounter.Start();
- for (int index = 0; index < 10000000; index++)
- {
- generator.NextDouble();
- }
- timeCounter.Stop();
-
- Console.WriteLine(
- "The time for the '" + generator + "' generator took '" +
- timeCounter.ElapsedMilliseconds + "' ms.");
-
- Console.Write("Example values are: ");
- for (int index = 0; index < 10; index++)
- {
- Console.Write(generator.NextDouble().ToString("0.000000 | "));
- }
- Console.WriteLine();
- }
- #endregion
-
- #region TestPerformance (LongRunning)
- /// <summary>
- /// Test performance
- /// </summary>
- [Test, Category("LongRunning")]
- public static void TestPerformance()
- {
- Stopwatch timeCounter = new Stopwatch();
-
- PerformGenerator(new Random(), timeCounter);
- PerformGenerator(new Random250Algorithm(), timeCounter);
- }
- #endregion
- }
- }
- }