C#生成随机int - 之谜

时间:2011-10-14 19:29:38

标签: c# random generator

我在生成随机整数的过程中发现了一些有趣的东西(至少对我来说),我无法向自己解释,所以我想我会在这里发布。

我的需求很简单:我正在生成随机整数(Int32)ID,旨在最大限度地减少冲突。生成时间不是问题。

我已尝试过这些方法来生成随机整数:

1)

   return rnd.Next();

其中rnd是类型为Random的类字段,带有来自方法#3的种子。

2)。

   return rnd.Next(Int32.MinValue, Int32.MaxValue);

其中rnd也是类型为Random的类字段,带有方法#3的种子。

3。)

   var buffer = new byte[sizeof(int)];
   using (var rng = new RNGCryptoServiceProvider())
   {
        rng.GetBytes(buffer);
   }            
   return BitConverter.ToInt32(buffer, 0);

注意:我还尝试将RNGCryptoServiceProvider作为类字段在初始化容器类时初始化一次以简化GC的工作,但我花了相同的时间来生成所以我认为这将是“更随机”。

4。)

   return new Random(Method3()).Next();

5。)

   return new Random(Method3()).Next(Int32.MinValue, Int32.MaxValue);

我知道,在每次调用时创建新的Random(int种子)非常耗时,但碰撞次数较少,对吧?

嗯,现在是神秘的一部分。我认为大多数碰撞都会有方法#1和#2,其中#1会稍微快一点,而且碰撞更少,碰撞最少的方法是#4和#5,其中#4会稍微快一点,而且方法#更多3会有某种妥协。

所以我做了一个测试来证明我的假设。我使用所提到的每种方法生成了10倍(以使其平均)一百万个随机数,并获得了生成一百万个数字所需的平均碰撞次数和平均时间。结果(如下)对我来说有点意外。

结果:持续时间为小时:分钟:秒:毫秒格式

Method1: AvgCollisions: 235, AvgDuration: 00:00:00.3561967
Method2: AvgCollisions: 116, AvgDuration: 00:00:00.4042033
Method3: AvgCollisions: 115, AvgDuration: 00:00:04.6037259
Method4: AvgCollisions: 234, AvgDuration: 00:00:09.2195856
Method5: AvgCollisions: 233, AvgDuration: 00:00:09.1788223

我再次进行了几次测试,它总是大致相同。

你也不奇怪吗?时间并不是我想象的那么多,但结果对我来说意味着,方法2是最好的生成随机数,因为它是最随机的,最快的,你可以设置一个最小和最大生成的数字。不知道Method2对Method3的预测程度有多大,因为我不知道如何测试它。

有人可以解释一下我做错了什么,或者为什么方法#4和#5没有碰撞最少,为什么碰撞的百分比总是一样的?它不应该是随机的吗?

修改 以下是我已完成此测试的Visual Studio 2010解决方案:http://bit.ly/nxLODw

2 个答案:

答案 0 :(得分:6)

唯一奇怪的行为是方法5。

在方法1,4中,生成0到int.MaxValue范围内的数字。

在方法2,3和5中,生成int.MinValue到int.MaxValue范围内的数字。

因此,对于方法2和方法3,你的范围大约是方法的两倍,与方法1,4相比,它们有大约一半的碰撞。这对我来说似乎很正常。

那么为什么方法5产生与方法1和4一样多的碰撞,即使它在更大的范围内生成数字?好吧,事实证明System.Random构造函数采用种子的绝对值。换句话说,它将随机序列的数量减少到可能的一半。因此,即使从较大范围获得数字,也可以从较少的不同序列中生成它们。

答案 1 :(得分:0)

当你在那里时,你可能想要将#3修改为:

        var buffer = new byte[sizeof(int)];

        using (var rng = new RNGCryptoServiceProvider())
        {
            rng.GetBytes(buffer);
        }

        return BitConverter.ToInt32(buffer, 0);

这a)保证你的数组是int的大小(而不是幻数4)和b)正确处理IDisposable所在的RNGCryptoServiceProvider