/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}