如何在运行时生成随机数?

时间:2010-12-14 15:27:00

标签: c# algorithm programming-languages random

由于计算机无法选择随机数(可以吗?)这个随机数是如何实际生成的。例如,在C#中我们说,

Random.Next()

里面发生了什么?

7 个答案:

答案 0 :(得分:14)

您可以结帐this article。根据{{​​3}},.NET中使用的具体实现基于Donald E. Knuth的减法随机数生成器算法。有关详细信息,请参阅documentation

答案 1 :(得分:6)

  

由于计算机无法选择随机数(可以吗?)

正如其他人所说,“随机”实际上是伪随机的。回答你的括号问题:是的,计算机可以选择真正随机的数字。这样做比伪随机数发生器的简单整数算法昂贵得多,并且通常不需要。但是,有些应用程序你必须具有不可预测的真正随机性:加密和在线扑克会立即浮现在脑海中。如果要么使用可预测的伪随机源,那么攻击者就可以更容易地解密/伪造消息,并且骗子可以找出谁拥有他们手中的内容。

.NET加密类有methods that give random numbers suitable for cryptography或游戏,其中有钱。至于它们如何工作:关于加密随机性的文献是广泛的;有关详细信息,请参阅任何优秀的大学本科密码学教科书。

也存在专用硬件来获取随机位。如果您需要从大气噪声中提取的随机数,请访问www.random.org。

答案 2 :(得分:4)

Knuth很好地涵盖了随机性主题。

我们并不是很了解随机。可预测的事物如何随机?然而,通过统计检验,伪随机序列似乎是完全随机的。

有三类随机生成器,放大了上面的评论。

首先,你有伪随机数生成器,如果你知道当前的随机数,那么很容易计算下一个随机数。如果您发现一些数字,这可以很容易地对其他数字进行逆向工程。

然后,有一些加密算法使这更加困难。我相信它们仍然是伪随机序列(与上面的评论所暗示的相反),但是具有非常重要的特性,即知道序列中的一些数字并不能明确如何计算其余数字。它的工作方式是加密例程倾向于对数字进行散列,因此如果一个位发生变化,则每个位都可能因此而发生变化。

考虑一个简单的模数生成器(类似于C rand()中的一些实现)

int rand(){   return seed = seed * m + a; }

如果m = 0且a = 0,这是一个糟糕的发生器,周期为1:0,0,0,0 ...... 如果m = 1且a = 1,它看起来也不是很随机:0,1,2,3,4,5,6 ......

但是如果你选择m和a作为2 ^ 16左右的素数,如果你随便检查,这将很好地看起来非常随机。但由于两个数字都是奇数,你会看到低位会切换,即数字交替为奇数和偶数。不是一个伟大的随机数发生器。并且由于32位数中只有2 ^ 32个值,根据定义,在最多2 ^ 32次迭代后,您将再次重复该序列,这使得生成器显然不是随机的。

如果你认为中间位是好的和加扰的,而较低的那些不是随机的,那么你可以用其中的一些构造一个更好的随机数发生器,将各个位异或一起使得所有比特被很好地覆盖了。类似的东西:

(rand1()>> 8)^ rand2()^(rand3()> 5)......

尽管如此,每个数字都在同步翻转,这使得这个可以预测。如果你得到两个连续值,它们是相关的,所以如果你绘制它们,你将在屏幕上得到线条。现在假设您有组合生成器的规则,因此顺序值不是下一个。 例如

v1 = rand1()>> 8 ^ rand2()...... v2 = rand2()>> 8 ^ rand5()..

并想象种子并不总是前进。现在你开始制作一些基于逆向工程更难预测的东西,而且序列更长。

例如,如果你每次都计算rand1(),但每次第3次只在rand2()中推进种子,那么组合它们的生成器可能不会重复任何一段时间。

现在假设您通过DES或其他加密算法抽取(相当可预测的)模数型随机数生成器。这会破坏比特。

显然,有更好的算法,但这会给你一个想法。 Numerical Recipes在代码中实现了许多算法并进行了解释。一个非常好的技巧:在表中生成一个而不是一个随机值块。然后使用一个独立的随机数生成器来选择一个生成的数字,生成一个新数字并替换它。这打破了相邻数字对之间的任何相关性。

第三类是基于硬件的实际随机数发生器,例如基于大气噪声

http://www.random.org/randomness/

根据目前的科学,这是真正随机的。也许有一天我们会发现它遵循一些基本规则,但目前,我们无法预测这些价值,就我们而言,它们是“真正”随机的。

如果你想看一些源代码,那么boost库有很好的Fibonacci生成器的C ++实现,伪随机序列的统治者。

答案 3 :(得分:4)

我只想在问题的第一部分(“可以吗?”部分)中添加答案.h

计算机可以生成(好吧,生成可能不是一个完全准确的单词)随机数(如,非伪随机)。具体地,通过使用通过专用硬件设备(例如,基于噪声产生随机性)或通过使用环境输入(例如,硬盘定时,用户输入事件定时)获得的环境随机性。

然而,这与第二个问题没有关系(Random.Next()的工作原理)。

答案 4 :(得分:2)

Random班级是pseudo-random number generator

它基本上是一个非常长但确定的重复序列。 “随机性”来自不同的位置。指定从哪里开始是通过为随机数生成器选择seed来完成的,例如可以通过使用系统时间或从另一个随机源获取随机种子来完成。 default Random constructor使用系统时间作为种子。

用于生成数字序列的实际算法记录在MSDN

  

Random类的当前实现基于Donald E. Knuth的减法随机数生成器算法。有关更多信息,请参阅D. E. Knuth。 “计算机编程的艺术,第2卷:半数值算法”。 Addison-Wesley,Reading,MA,第二版,1981年。

答案 5 :(得分:1)

计算机使用pseudorandom number generators。从本质上讲,它们通过种子编号开始工作,并在每次需要新的伪随机数时通过算法迭代它。

这个过程当然是完全确定的,所以给定的种子每次使用时都会生成完全相同的数字序列,但生成的数字形成统计上均匀的分布(大约),这很好,因为在大多数情况下所有你需要的场景是随机随机性。

通常的做法是使用当前系统时间作为种子,但如果需要更高的安全性,可以从物理来源(例如磁盘延迟)收集“熵”,以便生成更难预测的种子。在这种情况下,您还需要使用cryptographically strong random number generator,例如this

答案 6 :(得分:0)

我不知道太多细节,但我所知道的是,使用种子来生成随机数,然后基于使用该种子获得新数字的某种算法。

如果你得到基于相同种子的随机数,它们会经常相同。