数学领域,随机数是指一组完全没有规律的数列,也就是说要求要有一个无因果关系的随机事件。
但在计算机中,并没有真正意义的随机数。计算机中的随机数,都是由一个随机因子和一个复杂的随机函数产生。
在老版本的C++程序中,每次开始的随机因子都是相同的值,因此重复执行程序,得到的随机数都是相同的。
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int main()
{
cout<< rand()<<endl;
}
执行结果:
来源:(公众号:头发头发等等我)
在后续版本的C++中,已经修正了这种操作。在Python等其他语言中,每次在程序启动时执行random函数,结果也不相同。
但是无论是那种修复,都无法获得真正的随机函数。只能是更加接近我们需求的“完全随机”。
因此,C++提供一个srand方法,用来重置随机因子。一般情况下,我们使用时间戳来填充随机因子。
srand(unsigned(time(0)))
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int main()
{
srand(time(0));
cout<< rand()<<endl;
}
执行结果:
来源:(公众号:头发头发等等我)
在实际使用中,使用当时的时间戳已经可以得到较为接近的“随机数”。已经基本可以满足大多数程序的使用。
但是这种随机数的随机因子,是当时的时间戳。但是当时的时间戳是很容易被捕获到的,这并不是一个非常优秀的方法。历史上,计算机中随机数的发展,也确实复杂坎坷。
伪随机数生成器(PRNG)
伪随机数生成器是由冯诺依曼在 1946 年创造的。他的基本思想是从一个随机数种子开始,对其平方,然后取中间值。接下来重复对得到的数取平方并取中间值的过程,就会得到一个具有统计意义属性的随机数序列了。这也就是广为人知的平方取中法。
然而,冯诺依曼的方法并没有经得住时间的考验,因为不论从什么随机种子开始,序列最终都会落入某个短循环序列,比如:8100,6100,4100,8100,6100,4100……。序列中的数字是依赖于前一个数字的这种生成函数,上面的重复循环问题是不可避免的。
在 1999 年,随机数市场发生了一个巨大的变化,Intel 在其 i810 芯片组上集成了芯片级的随机数生成器。这样使得新的服务器都自带热噪声的本地源随机数生成能力——真正的随机数生成器(TRNG)。这很伟大,但是它始终没有软件 PRNG 快,所以加密软件依旧不得不依赖于伪随机数生成器(PRNG)。