我在生成随机整数时发现了一些有趣的事情(至少对我来说),但我无法自己解释,所以我想在这里发布它。
我的需求很简单:我正在生成随机整数(Int32)ID,并且旨在最小化碰撞。生成时间不是问题。
我尝试了以下几种方法来生成随机整数:
1.)
return rnd.Next();
其中rnd是类型为Random的类字段,其种子来源于方法#3。
2.)
return rnd.Next(Int32.MinValue, Int32.MaxValue);
在这里,rnd 再次是类型为 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倍(为了平均)100万个随机数,并记录了平均碰撞次数和生成100万个数字所需的平均时间。以下是结果,对我来说有点惊讶。
结果:持续时间以小时:分钟:秒:毫秒的格式呈现。
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
我再次运行了几次测试,结果基本相同。你也觉得很奇怪吗?虽然这些时间并没有给我带来惊喜,但对我而言,结果意味着Method2是生成随机数最好的方法,因为它是最随机、最快速且可以设置最小和最大生成数字。不知道Method2相对于Method3更可预测多少,因为我不知道该如何测试它。
有人能解释一下我错在哪里或者为什么方法#4和#5没有最小碰撞率,以及为什么碰撞率始终保持一致吗?这不应该是随机的吗?
编辑:这里是我做这个测试所用的Visual Studio 2010解决方案:http://bit.ly/nxLODw
new Random()
。只需执行一次即可。 - Jesse C. Slicer