使用C#的随机数

我正在寻找生成1到5百万之间的随机数。 这个过程不一定很快(虽然它会很好),但它必须尽可能随机(我知道什么都不是随机的)。 我有种子的各种数据源。

我不确定.NET Random类是否足够好。

这将用于选择中奖彩票。

System.Random类可能足够好了:

从有限的数字集合中以相等的概率选择伪随机数。 所选择的数字不是完全随机的,因为使用确定的数学算法来选择它们,但是出于实际目的它们是足够随机的。 Random类的当前实现基于Donald E. Knuth的减法随机数生成器算法。 有关更多信息,请参阅DE Knuth。 “计算机编程的艺术,第2卷:研究数学算法”。 Addison-Wesley,Reading,MA,第二版,1981。

您唯一需要注意的是,您不会经常重复使用相同的种子:

如果重复使用相同的种子,则生成相同的数字序列。 产生不同序列的一种方法是使种子值与时间相关,从而与每个新的Random实例产生不同的序列。

如果需要加密随机数,请使用System.Security.Cryptography.RNGCryptoServiceProvider类或使用RandomNumberGenerator.Create()工厂方法创建默认配置的随机数生成器。

实际上我最近在不同类型的PRNG上阅读了一篇非常好的文章,以及它们在几种不同的随机性测试方面的表现。 不幸的是,我现在似乎无法找到它。 然而,它的要点是,几乎所有流行编程语言中的默认随机数生成器都非常天真且具有相当大的偏差。

另一个答案已经提到,无论算法多么复杂,对于加密应用程序来说,根本没有PRNG。 这是真的。 既然你提到这将用于“选择中奖票”,那么我们暂时忽略它。

.NET System.Random类使用的Knuth算法主要针对速度而非随机分布进行优化。 对于许多目的而言,它是“随机的”,大多数应用程序从不偏离太远,但在(a)游戏和(b)统计模拟领域,大多数人似乎认为这是一个糟糕的选择。 它比以前在旧库中默认的LCG更好,但你仍然不想将它用于乐透之类的东西。

不要误以为你只是使用加密源。 加密RNG的问题在于它们填充了一个字节流,但是将它转换为xy之间的单个随机整数需要你做一些模运算(或舍入 – 两种方式相同的结果)。 如果你的随机范围没有完全均匀地划分为由字节长度定义的2的幂,那么你最终会得到较低数字的偏差。 生成的数据具有高熵,但您的结果会有偏差。

举一个简单的例子,让我们说你从1到10得到一个“完美”的随机数,现在你想把它变成1到7之间的随机数。你怎么做? 简单地计算result % 7将严重偏向数字1-3。 在使用加密RNG时,有一些方法可以减少偏差,但我想说的是加密RNG是为加密应用而设计的,而使用其中一种进行蒙特卡罗模拟通常不是最好的主意。

据我所知,目前在游戏应用中常用的最受欢迎的“好”PRNG是Mersenne Twister 。 这里有一个.NET实现 。 该算法通过所有Diehard测试进行随机分布; 当您使用随机数进行概率和统计应用时,它几乎没有偏差,是一个不错的选择。

GNU科学图书馆也有许多RNG算法 ,毫不奇怪,Mersenne Twister是最重要的。 不过,有些其他人值得关注好奇心。 RANLUX在死硬测试IIRC上也得分很高。

当然,埃里克对他的评论是正确的; 如果您对随机数字的“随机性”没有具体的技术要求,那么所有这些信息都是徒劳的。 我使用的定义适用于影响力相对较小的赌博/博彩应用程序(即不是每天有数百万访问者的主要注册赌博网站 – 对这些网站的随机性有更严格的规定)。

请参阅Jon Skeet的博客文章Revisiting Randomness ,对如何使用Randomness进行了非常好的评论:

重新审视随机性
几乎每个包含“随机”和“重复”字样的Stack Overflow问题都有相同的基本答案。 它是.NET,Java中最常见的“陷阱”之一,毫无疑问是其他平台:创建一个新的随机数生成器而不指定种子将取决于当前的时刻。 与您创建和使用随机数生成器的频率相比,计算机测量的当前时间不会经常变化 – 因此重复创建Random的新实例并使用它一次的代码最终将显示出大量重复。

更多…

要生成随机数,请创建Random类的对象,然后使用此对象的Next函数生成随机数。 它有很多重载,如:

 Next(int minimum, int maximum); Next(int Maximum); 

您可以在其中指定随机数之间的最小和最大范围。

代码段:

 Random random = new Random(); int maxValue = 100; int r = random.Next(maxValue); 

System.Random类非常有问题,并且不符合要求。 从理论上讲,它应该提供比许多其他伪随机发生器更好的结果。 它是第二版“C中的数字配方”第283页提供的Lagged Fibonacci Generator(LFG)的示例C代码的直接和字面端口(代码在以后的版本中重写)。 LFG使用比许多其他库(例如,Java)使用的线性同余生成器(LCG)更好的算法。

不幸的是,微软的System.Random类的实现有一个错误。 有关详细信息,请参阅http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug 。 当打算输入’31’时,似乎有人意外输入’21’。 这会破坏算法的伪随机特性。 该链接包括来自MS的解释,说明为什么他们觉得在此阶段无法修复错误。

如果您正在寻找真正的随机数,那么您应该考虑使用使用自然现象的在线随机数生成器,例如http://www.random.org ,它使用大气噪声。 真随机数也为伪随机数生成器提供了良好的种子。

Sipwiz在他的回答中展示了如何在C#中使用它:在C#中生成随机值 。 它也在这里讨论: http : //www.vcskicks.com/random-number-generator.php 。

随机数生成器有很多角度。 一个有趣的替代实现是ISSAC(ttp://burtleburtle.net/bob/rand/isaac.html),它也包含对偏见等的良好讨论,并且还有一个C#版本( http://burtleburtle.net) /bob/rand/isaacafa.html )。

.NET的Random应该没问题:

 var random = new Random(System.DateTime.Now.Millisecond); int randomNumber = random.Next(1, 5000000);