我正在使用静态类为程序提供随机值,但是实现等效于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()是如何工作的。

最佳答案

《 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);
    }
}

09-25 17:29
查看更多