c#生成随机int - mystery
本文关键字:mystery int 随机 | 更新日期: 2023-09-27 18:11:13
在生成随机整数时,我发现了一些有趣的事情(至少对我来说),我无法向自己解释,所以我想我将在这里发布。
我的需求很简单:我正在生成随机整数(Int32) id,目标是尽量减少碰撞。生成时间不是问题。
我已经尝试了这些方法来生成随机整数:
1)。
return rnd.Next();
其中rnd是方法#3中带有Seed的随机类型的类字段。
2)。
return rnd.Next(Int32.MinValue, Int32.MaxValue);
其中rnd仍然是来自方法#3的带有Seed的随机类型的类字段。
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万个随机数所需的平均碰撞次数和平均时间。(下面的)结果让我有点吃惊。
结果:duration是hours:minutes:seconds: milliseconds格式
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
唯一奇怪的行为是方法5。
在方法1、4中,生成一个0到int.MaxValue范围内的数字。
在方法2、3和5中,生成一个int范围内的数字。MinValue到int.MaxValue.
对于方法2和3,你有一个大约两倍大的范围,与方法1和4相比,它们有大约一半的碰撞。这在我看来很正常。
那么为什么方法5产生和方法1和方法4一样多的碰撞,即使它产生的数字范围更大?好的,结果是System.Random
构造函数取种子的绝对值。换句话说,它将随机序列的数量减少到原来的一半。因此,即使您从更大的范围获得数字,您也可以从更少的不同序列生成它们。
当你在那里,你可能想修改#3为:
var buffer = new byte[sizeof(int)];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(buffer);
}
return BitConverter.ToInt32(buffer, 0);
这a)保证你的数组的大小是int(而不是幻数4)和b)正确处置RNGCryptoServiceProvider
是IDisposable