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

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

Random.Next() 

里面发生了什么?

你可以查看这篇文章 。 根据文档 ,.NET中使用的具体实现基于Donald E. Knuth的减法随机数生成器算法。 有关更多信息,请参阅DE Knuth。 “计算机编程的艺术,第2卷:研究数学算法”。 Addison-Wesley,Reading,MA,第二版,1981 。

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

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

.NET加密类的方法可以为随机数提供适合加密或游戏的随机数字 。 至于它们如何工作:关于加密随机性的文献是广泛的; 有关详细信息,请参阅任何优秀的大学本科密码学教科书。

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

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 ++实现,如果你想看到一些源代码,它们是伪随机序列的统治者。

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

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

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

Random类是伪随机数生成器 。

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

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

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

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

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

通常的做法是使用当前系统时间作为种子,但是如果需要更高的安全性,则可以从诸如磁盘等待时间的物理源收集“熵”以便生成更难以预测的种子。 在这种情况下,您还需要使用加密强大的随机数生成器,例如此类 。

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

如果您根据相同的种子获得随机数,它们将经常相同。