#### /Utilities/Math/RandomBase.cs

#
C# | 262 lines | 133 code | 25 blank | 104 comment | 4 complexity | 47761b5ab963c6850bd4d0c0c9474e44 MD5 | raw file
``````
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:

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

}

}

}

``````