First we need a base class for overriding System.Random. We will call it RandomBase and it will be used to cover all the methods implemented by System.Random. We'll only be leaving the Next() method unimplemented but as abstract so the parent classes can implement the method differently for each algorithm. Everything else will be the same.
There are a few utility functions for type conversion included and we'll expose the base class random number generator for the cases when we'll need it.
public abstract class RandomBase: Random
{
#region Constructors
public RandomBase() { }
public RandomBase(int seed) : base(seed) { }
#endregion
#region Methods
protected int GetBaseNextInt32()
{
return base.Next();
}
protected uint GetBaseNextUInt32()
{
return ConvertToUInt32(base.Next());
}
protected double GetBaseNextDouble()
{
return base.NextDouble();
}
#endregion
#region Overrides
public abstract override int Next();
public override int Next(int maxValue)
{
return Next(0, maxValue);
}
public override int Next(int minValue, int maxValue)
{
return Convert.ToInt32((maxValue - minValue) * Sample() + minValue);
}
public override double NextDouble()
{
return Sample();
}
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)));
}
}
protected override double Sample()
{
// generates a random number on [0,1)
return Convert.ToDouble(Next()) / 2147483648.0; // divided by 2^31 (Int32 absolute value)
}
#endregion
#region Utility Methods
protected static UInt32 ConvertToUInt32(Int32 value)
{
return BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
protected static Int32 ConvertToInt32(UInt32 value)
{
return BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
}
protected static Int32 ConvertToInt32(UInt64 value)
{
return BitConverter.ToInt32(BitConverter.GetBytes(value & 0x000000007fffffff) , 0);
}
#endregion
}
Part II: Implementing an algorithm.
The algorithms are pretty standard and I found implementations for the algorithms used in this article from these two sources:
To implement we just have to put together the constructors and implement the Next() method as in the Quick class below. I had to modify each algorithm slightly to take advantage of the inheritance in place and work out some small bugs that popped up.
public class Quick : RandomBase
{
#region Constructors
public Quick() : this(Convert.ToInt32(DateTime.Now.Ticks & 0x000000007FFFFFFF)) { }
public Quick(int seed)
: base(seed)
{
i = Convert.ToUInt64(GetBaseNextInt32());
}
#endregion
#region Member Variables
private static readonly uint a = 1099087573;
private ulong i;
#endregion
#region Methods
public override int Next()
{
#region Execution
i = a * i; // overflow occurs here!
return ConvertToInt32(i);
#endregion
}
#endregion
}
Part III. Executing the Algorithms
The beauty of this approach is that we can treat each algorithm implementations as if it were a System.Random object.
Step 1: Declare the Variable:
private Random m_quick;
Step 2: Initialize:
m_quick = new RandomNumberGeneration.Quick();
Step 3: Execute (just as if it were a System.Random object)
m_quick.NextDouble();
Hopefully you'll find the project library useful.
Until next time,
Happy Coding
Humberto DiazPosted Jan 5, 2016, 2:50 PM
Use earlier Cryptography.RandomNumberGenerator to generate truly random sequences
theo philusPosted Feb 11, 2009, 7:13 AM
please can you help me on how to generate alphanumeric codes using a simple c#.net app. please send me the codes through [email protected] waiting to hear from you.
SameditedPosted Sep 1, 2008, 2:13 PMEdited Sep 1, 2008, 2:21 PM
Sorry for the billion duplicate posts. I kept getting an error upon submitting and I assumed it wasn't posting my comments. Anyway, I managed to fix the error I was getting. When asking for a number within a range, it would favor the numbers between the Min and Max values, and only output the Min and Max half as much as the rest of them. For instance, if 1 and 10 were both output twice, odds are the numbers 2-9 would have been output four times each. The solution to this is to check if the output number is the min or max value, if it isn't (and it most likely isn't) then calculate a random number again based on a few coin flips to increase the chances of Min or Max being the output. I haven't tested it for any range above 1-10, but it appears to work. Just go to RandomBase and replace the public override int Next (min, max) function with this: public override int Next(int minValue, int maxValue) { int temp; int Random = Convert.ToInt32((maxValue - minValue - 1) * Sample() + minValue); if (Random != minValue || Random != maxValue) { temp = Convert.ToInt32((maxValue+1 - minValue - 1) * Sample() + minValue); if (temp == (int)Math.Floor((double)minValue+(double)maxValue/2)) { temp = Convert.ToInt32((3 - 1 - 1) * Sample() + 1); if (temp == 1) { Random = minValue; } else { Random = maxValue-1; } } } return Random; }
SameditedPosted Sep 1, 2008, 1:01 PMEdited Sep 1, 2008, 2:16 PM
Doesn't like the min and max values
SameditedPosted Sep 1, 2008, 1:01 PMEdited Sep 1, 2008, 2:17 PM
Doesn't like the min and max values
SameditedPosted Sep 1, 2008, 1:01 PMEdited Sep 1, 2008, 2:17 PM
Doesn't like the min and max values
SameditedPosted Sep 1, 2008, 1:01 PMEdited Sep 1, 2008, 2:17 PM
Doesn't like the min and max values
SameditedPosted Sep 1, 2008, 1:01 PMEdited Sep 1, 2008, 2:17 PM
Doesn't like the min and max values
SameditedPosted Sep 1, 2008, 1:00 PMEdited Sep 1, 2008, 2:19 PM
I recorded the amount of outputs each number between 1 and 10 would get on a run through of 50000 number generations. I'll show you two results of the many I've done using multiple algorithms: The Average is: 5 One: 2664 Two: 5525 Three: 5623 Four: 5485 Five: 5564 Six: 5622 Seven: 5543 Eight: 5679 Nine: 5544 Ten: 2751 The Average is: 5 One: 2802 Two: 5559 Three: 5524 Four: 5524 Five: 5542 Six: 5574 Seven: 5622 Eight: 5615 Nine: 5452 Ten: 2786 Anyone notice that 1 and 10 are half as common as the rest? Any ideas?
Hugo RojoeditedPosted Dec 30, 2007, 3:25 PMEdited Dec 30, 2007, 3:30 PM
The method Next should never return the maxValue passed as a parameter, so you should substract 1 like this: public override int Next(int minValue, int maxValue) { return Convert.ToInt32((maxValue - minValue - 1) * Sample() + minValue); }
JoshuaPosted May 7, 2007, 3:22 AM
The code contains several Magic Numbers that are not explained in the article, nor in the code comments. The RandomBase implementation of Next(minValue, maxValue) treats maxValue as an Inclusive Upper Bound, while the base Random inmplementation states that maxValue is an Exclusive Upper Bound, so numbers generated from this implementation are larger than expected. Finally this implementation does not produce good distributions. When run over 65535 times with min 1 max 20, Random gives distribution for all possibilities approaching 1/20 or 0.05, however these classes ALL produce distributions of 1/2 that, or 0.025 for both 1 and 20. This code is what really isn't random.