你用过.net的System.Random类吗?.用过的人会发现随机数生成器类不能很好的产生随机数,而且性能不太好。用随机数生成器类的用途很多,但由于System.Random不太好的表现给我们造成了很大的不便。为了解决这个问题我们可以重新写一个产生随机数类来弥补System.Random的不足之处。
首先我们现在重写一个System.Random的基类RdomBase,它将实现System.Random中所实现的所有方法,但我们将保留Next()方法作为抽象方法,以便继承类根据不同的运算规则来实现它。在随机数生成器类中编写了几个有用的类型转换方法以备读者需要时使用。基类RdomBase的代码如下:
public abstract class RdomBase: Random
{
#region 构造函数
public RdomBase()
{
}
public RdomBase(int seed) : base(seed)//执行基类构造方法
{
}
#endregion
#region 方法
protected int GetBaseNextInt32()//获取下一个32位整数的随机数
{
return base.Next();
}
protected uint GetBaseNextUInt32() //获取下一个32位无符号整数的随机数
{
return ConvertToUInt32(base.Next());
}
protected double GetBaseNextDouble() //获取下一个双精度的随机数
{
return base.NextDouble();
}
#endregion
#region 重写
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)//计算方法具体介绍见 http://www.qbrundage.com/michaelb/pubs/essays/random_number_generation.html
{
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 =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()
{
// 在[0,1)范围产生一个随机数
return Convert.ToDouble(Next()) / 2147483648.0; // 除以正整数2^31
}
#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
}
我们再做一个NewRandom类,它从上边的类继承而来,在这个类里我们实现Next()的抽象方法。代码如下:
public class NewRandom : RdomBase
{
#region 构造函数
public NewRandom() : this(Convert.ToInt32(DateTime.Now.Ticks & 0x000000007FFFFFFF)) { }
public NewRandom(int seed): base(seed)
{
i = Convert.ToUInt64(GetBaseNextInt32());
}
#endregion
#region 私有成员
private static readonly uint a = 1099087573;
private ulong i=1;
#endregion
#region 方法
public override int Next()//重写父类抽象方法
{
#region Execution
i = a * i; // overflow occurs here!
return ConvertToInt32(i);
#endregion
}
#endregion
}
现在所有代码都介绍完了,读者可以把代码嵌入到自己的程序里试验一下这个随机数生成器类,比如在程序里写段如下代码:
private NewRandom m_NewRandom;
m_NewRandom = new RandomNumberGeneration.NewRandom();
m_NewRandom.NextDouble();
试验后你是否感觉到用起来比System.Random爽快、好用?当然这只是一种思路,读者可以根据自己的情况调整以上代码来达到更适合自己程序的随机数生成器。