我正在开发一个静态类来为我的程序提供随机值,但实现Random.Next(int maxValue)功能的等价物存在一些问题:
public class CRandom {
static readonly byte[] randomSet;
static readonly Func<int> closedIndex;
static CRandom() {
randomSet = new byte[60000000];
closedIndex = _ClosedIndex(0);
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
Gen.GetBytes(randomSet);
}
public static int Next() {
int index = closedIndex();
return Convert.ToInt32(randomSet[index]);
}
public static int Next(int maxValue) {
int index = closedIndex();
byte[] remainingSet = randomSet.Skip(index + 1).ToArray();
byte next = remainingSet.First(x => Convert.ToInt32(x) < maxValue);
return Convert.ToInt32(next);
}
public static Func<int> _ClosedIndex(int seed) {
// seed is the initial value
int _index = seed - 1;
Func<int> del = new Func<int>(() =>
{ // always returns auto-incremented value
_index++;
return _index;
});
return del;
}
}
基本上它的作用是填充随机值的静态/只读字节数组,在Next(maxValue)方法的情况下,只获取范围内但之前未使用过的下一个值。然而,在循环中尝试Next(100)会给出这些结果,这显然不是随机的:
53 20 20 34 34 73 73 73 73
这也是一种非常慢的方式。我确信有更好的方法,但我不知道Random.Next()是如何工作的。
答案 0 :(得分:3)
MSDN杂志有一个关于这个确切主题的very detailed article 这比你想象的要复杂得多。
他写了下面的课;但是,请阅读文章,了解有关随机性的重要说明。
public class CryptoRandom : Random
{
private RNGCryptoServiceProvider _rng =
new RNGCryptoServiceProvider();
private byte[] _uint32Buffer = new byte[4];
public CryptoRandom() { }
public CryptoRandom(Int32 ignoredSeed) { }
public override Int32 Next()
{
_rng.GetBytes(_uint32Buffer);
return BitConverter.ToInt32(_uint32Buffer, 0) & 0x7FFFFFFF;
}
public override Int32 Next(Int32 maxValue)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException("maxValue");
return Next(0, maxValue);
}
public override Int32 Next(Int32 minValue, Int32 maxValue)
{
if (minValue > maxValue)
throw new ArgumentOutOfRangeException("minValue");
if (minValue == maxValue) return minValue;
Int64 diff = maxValue - minValue;
while (true)
{
_rng.GetBytes(_uint32Buffer);
UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0);
Int64 max = (1 + (Int64)UInt32.MaxValue);
Int64 remainder = max % diff;
if (rand < max - remainder)
{
return (Int32)(minValue + (rand % diff));
}
}
}
public override double NextDouble()
{
_rng.GetBytes(_uint32Buffer);
UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0);
return rand / (1.0 + UInt32.MaxValue);
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
_rng.GetBytes(buffer);
}
}
答案 1 :(得分:0)
试试我的解决方案:
public sealed class SecureRandom : Random {
private readonly RandomNumberGenerator _rng;
public SecureRandom() {
_rng = new RNGCryptoServiceProvider();
}
public SecureRandom(int seed) {
var rgb = BitConverter.GetBytes(seed);
_rng = new RNGCryptoServiceProvider(rgb);
}
public override int Next() {
var data = new byte[sizeof (int)];
_rng.GetBytes(data);
return BitConverter.ToInt32(data, 0) & (int.MaxValue - 1);
}
public override int Next(int maxValue) {
return Next(0, maxValue);
}
public override int Next(int minValue, int maxValue) {
if (minValue > maxValue) {
throw new ArgumentOutOfRangeException("minValue", minValue, "minValue must be less than or equals to maxValue");
}
return (int) Math.Floor(minValue + (maxValue - minValue) * NextDouble());
}
public override double NextDouble() {
var data = new byte[sizeof (uint)];
_rng.GetBytes(data);
var randUint = BitConverter.ToUInt32(data, 0);
return randUint / (uint.MaxValue + 1.0);
}
public override void NextBytes(byte[] data) {
_rng.GetBytes(data);
}
public override string ToString() {
return _rng.ToString();
}
public override bool Equals(object obj) {
return _rng.Equals(obj);
}
public override int GetHashCode() {
return _rng.GetHashCode();
}
}