使用Random.NextBytes()中的最小值和最大值创建随机整数

时间:2015-08-13 10:18:49

标签: c# random

标题几乎说明了一切。当然,我知道我可以使用Random.NextInt(),但我想知道是否有办法将无界随机数据转化为有界而无统计偏差。 (这意味着没有RandomInt() % (maximum-minimum)) + minimum)。当然有一种类似的方法,它不会在输出的数据中引入偏差吗?

3 个答案:

答案 0 :(得分:2)

如果您认为这些位是随机分布的,我建议:

  • 生成足够的字节以获取范围内的数字(例如,1个字节可获得0-100范围内的数字,2个字节可获得0-30000范围内的数字等)。
  • 仅使用这些字节中足够的位来覆盖您需要的范围。因此,例如,如果您生成0-100范围内的数字,请获取您生成的字节的最后7位
  • 将您所获得的位解释为[0,2 n )范围内的数字,其中n是位数
  • 检查号码是否在您想要的范围内。至少应该是平均一半的时间
  • 如果是这样,请使用它。如果没有,请重复上述步骤,直到 的数字在正确的范围内。

使用所需的位数是实现这一目标的关键 - 你可以丢弃最多一半的字节数,但不会超过这个数,假设分布良好。 (如果你在一个很好的二进制范围内生成数字,你将不需要扔掉任何东西。)

实施作为练习留给读者:)

答案 1 :(得分:1)

您可以尝试使用以下内容:

public static int MyNextInt(Random rnd, int minValue, int maxValue)
{
    var buffer = new byte[4];
    rnd.NextBytes(buffer);
    uint num = BitConverter.ToUInt32(buffer, 0);

    // The +1 is to exclude the maxValue in the case that 
    // minValue == int.MinValue, maxValue == int.MaxValue
    double dbl = num * 1.0 / ((long)uint.MaxValue + 1);

    long range = (long)maxValue - minValue;
    int result = (int)(dbl * range) + minValue;
    return result;
}

完全未经测试......我无法保证结果真的是伪随机的......但创建doubledbl)数字的想法与Random课程。uint.MaxValue。只有我使用int.MaxValue作为基础,而不是buffer。这样我就不必检查ByteArrayOutputStream out = new ByteArrayOutputStream(); YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null); yuvImage.compressToJpeg(new Rect(0, 0, width, height), 50, out); byte[] imageBytes = out.toByteArray(); Bitmap image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); iv.setImageBitmap(image); 的负值。

答案 2 :(得分:1)

我提出了一个基于NextBytes的随机整数生成器。 由于使用Int64作为位操作的表示,该方法在正字Int32的字大小范围内平均丢弃了9.62%的位。

字符大小为22位时发生最大位丢失,在字节范围转换中使用64位丢失的64位。在这种情况下,比特效率为68.75%

此外,由于将未绑定范围限制为最大值,因此25%的值会丢失。

小心在返回的IEnumerable上使用Take(N),因为它是一个无限的生成器。

我使用512个长值的缓冲区,因此它一次生成4096个随机字节。如果您只需要几个整数的序列,请将缓冲区大小从512更改为更优的值,直到1。

public static class RandomExtensions
{
    public static IEnumerable<int> GetRandomIntegers(this Random r, int max)
    {
        if (max < 1)
            throw new ArgumentOutOfRangeException("max", max, "Must be a positive value.");

        const int longWordsTotal = 512;
        const int bufferSize = longWordsTotal * 8;
        var buffer = new byte[bufferSize];
        var wordSize = (int)Math.Log(max, 2) + 1;

        while(true)
        {
            r.NextBytes(buffer);
            for (var longWordIndex = 0; longWordIndex < longWordsTotal; longWordIndex++)
            {
                ulong longWord = BitConverter.ToUInt64(buffer, longWordIndex);
                var lastStartBit = 64 -  wordSize;
                var count = 0;
                for (var startBit = 0; startBit <= lastStartBit; startBit += wordSize)
                {
                    count ++;                       
                    var mask = ((1UL << wordSize) - 1) << startBit;                 
                    var unboundValue = (int)((mask & longWord) >> startBit);
                    if (unboundValue <= max)
                        yield return unboundValue;
                }
            }
        }       
    }
}