nav*_*een 12 c# random algorithm programming-languages
由于计算机无法选择随机数(可以吗?)这个随机数是如何实际生成的.例如在C#中我们说,
Random.Next()
Run Code Online (Sandbox Code Playgroud)
里面发生了什么?
Dar*_*rov 14
你可以查看这篇文章.根据文档,.NET中使用的具体实现基于Donald E. Knuth的减法随机数生成器算法.有关更多信息,请参阅DE Knuth."计算机编程的艺术,第2卷:半数值算法".Addison-Wesley,Reading,MA,第二版,1981.
由于计算机无法选择随机数(可以吗?)
正如其他人所说,"随机"实际上是伪随机的.回答你的括号问题:是的,计算机可以选择真正随机的数字.这样做比伪随机数发生器的简单整数算法昂贵得多,并且通常不需要.但是,有些应用程序必须具有不可预测的真正随机性:立即想到加密和在线扑克.如果要么使用可预测的伪随机源,那么攻击者可以更容易地解密/伪造消息,并且骗子可以找出谁拥有他们手中的东西.
.NET加密类的方法可以为随机数提供适合加密或游戏的随机数字.至于它们如何工作:关于加密随机性的文献是广泛的; 有关详细信息,请参阅任何优秀的大学本科密码学教科书.
还存在专用硬件以获得随机位.如果您需要从大气噪声中提取的随机数,请访问www.random.org.
Knuth 很好地涵盖了随机性主题。
我们不太了解随机。可预测的东西怎么可能是随机的?然而,通过统计测试,伪随机序列似乎是完全随机的。
随机生成器分为三类,放大了上面的评论。
首先,你有伪随机数生成器,如果你知道当前的随机数,就很容易计算下一个。如果您发现一些数字,这可以轻松地对其他数字进行逆向工程。
然后,有密码算法使这变得更加困难。我相信它们仍然是伪随机序列(与上面的评论所暗示的相反),但是具有非常重要的特性,即知道序列中的一些数字并不能使如何计算其余数字变得显而易见。它的工作方式是加密例程倾向于对数字进行散列,因此如果一位发生变化,那么每一位都同样有可能因此而发生变化。
考虑一个简单的模生成器(类似于 C rand() 中的一些实现)
int rand() { 返回种子 = 种子 * 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 库具有斐波那契生成器的优秀 C++ 实现,如果您想查看一些源代码,它是伪随机序列的统治者。