如何使用RNGCryptoServiceProvider获得大于256的随机数?

时间:2018-12-10 06:00:14

标签: c# random

如何使用RNGCryptoServiceProvider获得大于256的随机数?

代码:

private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();

byte[] randomNumber = new byte[1];

//Fill the array with a random value.   

rngCsp.GetBytes(randomNumber);

2 个答案:

答案 0 :(得分:7)

用1-8个字节填充数组,并使用BitConverter提取一个整数。

    static ulong RandomUInt64()
    {
        var rng = new RNGCryptoServiceProvider();
        var bytes = new byte[8];
        rng.GetBytes(bytes);
        return BitConverter.ToUInt64(bytes);
    }

如果要在特定范围内生成随机数,并且还希望保留分布,则应生成一系列数字并丢弃不在预期范围内的值(Monte Carlo方法)。如果您考虑使用安全的密码随机数生成器,我怀疑这是您想要的行为。

    static int Random(RandomNumberGenerator rng, int min, int max)
    {
        if (min > max) throw new ArgumentException(nameof(min));
        if (min == max) return min;

        var bytes = new byte[4];

        long diff = max - min;

        while (true)
        {
            rng.GetBytes(bytes);

            var rand = BitConverter.ToUInt32(bytes);
            var remainder = (1 + (long) uint.MaxValue) % diff;

            if (rand < max - remainder)
            {
                return (int) (min + (rand % diff));
            }
        }
    }

调用提供程序时会产生大量开销,因此请考虑缓冲对 GetBytes 的调用。为了更快地生成数字,除了丢弃超出范围的样本(以保留分布)之外,您还可以从随机缓冲区中最多选择 log(range)/ log(2)位

public class RandomGenerator
{
    private readonly RandomNumberGenerator _rng;

    public RandomGenerator(RandomNumberGenerator rng)
    {
        _rng = rng;
    }

    public IEnumerable<int> Next(ulong range)
    {
        var buffer = new byte[8 * 512];
        var bits = (int) Math.Ceiling(Math.Log(range) / Math.Log(2));
        var mask = (ulong) ~(~0 << bits);

        while (true)
        {
            _rng.GetBytes(buffer);

            for (var i = 0; i < buffer.Length / 8; i += 8)
            {
                var num = BitConverter.ToUInt64(buffer, i);
                var n = num & mask;

                if (n <= range - 1)
                {
                    yield return (int) n;
                }
            }
        }
    }

    public IEnumerable<int> Next(int min, int max)
    {
        if (min > max) throw new ArgumentOutOfRangeException(nameof(min));
        var range = (ulong) Math.Abs(max - min);
        return Next(range).Select(r => r + min);
    }
}

这将为您提供有用的API:

  var rng = new RNGCryptoServiceProvider();
  var random = new RandomGenerator(rng);
  var randomValues = random.Next(-1000, 1000).Take(100).ToArray();

答案 1 :(得分:3)

您是否有任何理由需要对大于256的随机数使用RNGCryptoServiceProvider?

如emert117所述,字节的最大值为255。

如果需要随机数,可以尝试使用Random类。

Random _randomizer = New Random();
int randomNumber = _randomizer.Next(0,512);