【发布时间】:2014-07-27 14:11:49
【问题描述】:
我注意到 c# 中随机数生成的一个奇怪问题,看起来集合(模式)的重复次数比您预期的要多。
我正在编写一种生成激活码的机制,即一系列 7 个数字(范围 0-29)。 算一下,应该有 30^7(220 亿)个可能的激活码组合。基于此,在生成第 10 亿个代码之前获得重复激活码的可能性极小。然而运行我的测试,我在大约 60,000 次迭代后开始得到重复的代码,这非常令人惊讶。我也尝试过使用 RNGCryptoServiceProvider 获得类似的结果,我在大约 100,000 次迭代时得到重复。
我真的很想知道这是否是 .Net 中随机数生成的错误/限制,或者我做错了什么。
以下代码是验证生成代码唯一性的测试:
static void Main(string[] args)
{
Random rand = new Random();
RandomActivationCode(rand, true);
Console.Out.WriteLine("Press enter");
Console.ReadLine();
}
static void RandomActivationCode(Random randomGenerator)
{
var maxItems = 11000000;
var list = new List<string>(maxItems);
var activationCodes = new HashSet<string>(list);
activationCodes.Clear();
DateTime start = DateTime.Now;
for (int i = 0; i < maxItems; ++i)
{
string activationCode = "";
for (int j = 0; j < 7; ++j)
{
activationCode += randomGenerator.Next(0,30) + "-";
}
if (activationCodes.Contains(activationCode))
{
Console.Out.WriteLine("Code: " + activationCode);
Console.Out.WriteLine("Duplicate at iteration: " + i.ToString("##,#"));
Console.Out.WriteLine("Press enter");
Console.ReadLine();
Console.Out.WriteLine();
Console.Out.WriteLine();
}
else
{
activationCodes.Add(activationCode);
}
if (i % 100000 == 0)
{
Console.Out.WriteLine("Iteration: " + i.ToString("##,#"));
Console.Out.WriteLine("Time elapsed: " + (DateTime.Now - start));
}
}
}
我的解决方法是使用 10 个数字激活码,这意味着测试运行时不会生成任何重复值。测试运行多达 1100 万次迭代(之后会耗尽内存)。
【问题讨论】:
-
30^7 (22billion) possible combinations...extremely unlikely to get a duplicate [...]before the 1 billionth code...- 生日悖论? -
为什么会随机生成激活码?即使这样,您仍然必须存储它们,以便您可以检查激活。所以你可以随时检查一个是否已经存在,如果是,则生成新的。
-
@ErnodeWeerd 同意,我在帖子中提到了我使用 10 个字符的激活码作为解决方法