【发布时间】:2011-12-08 00:39:35
【问题描述】:
我在生成随机整数时发现了一些有趣的事情(至少对我来说),我无法向自己解释,所以我想我会在这里发布。
我的需求很简单:我正在生成随机整数 (Int32) ID,并且旨在最大限度地减少冲突。生成时间不是问题。
我已经尝试过这些生成随机整数的方法:
1.)
return rnd.Next();
其中 rnd 是方法 #3 中带有种子的 Random 类型的类字段。
2.)
return rnd.Next(Int32.MinValue, Int32.MaxValue);
其中 rnd 再次是方法 #3 中带有种子的 Random 类型的类字段。
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 seed) 非常耗时,但冲突较少,对吧?
好吧,现在是神秘的部分。我假设大多数碰撞都会有方法#1和#2,其中#1会稍微快一点,更无碰撞,最少的碰撞会有方法#4和#5,其中#4会稍微快一点,更无碰撞和方法# 3 会是某种妥协。
所以我做了一个测试来证明我的假设。我使用每种提到的方法生成了 10 倍(使其平均)一百万个随机数,并计算了平均碰撞次数和生成一百万个数字所需的平均时间。结果(如下)让我有点吃惊。
结果:duration是小时:分钟:秒:毫秒格式
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
【问题讨论】:
-
您确定在第一个结果中看到的碰撞次数吗?鉴于this(以及这里的无数其他类似讨论——这是前五个编程误解之一),其他一切都是有道理的。你能发布你的测试用例吗?
-
您的#4/#5 假设是错误的。你永远不应该为每个随机数的需要调用
new Random()。只做一次。 -
+1 为迈克尔·佩罗塔。
and a zillion other similar discussions here -
致 Michael Petrotta:我发布了 VS2010 soultion,它正在编辑中。我知道 Random 类默认由系统时钟播种,这就是为什么我每次都从 RNGCryptoServiceProvider 给它新的随机种子,还是意味着它在每次 Next() 调用中使用系统时钟来计算?