研究过随机数吗?我们都知道电脑里面的随机数其实只是看上去是随机的,产生的过程都是确定的。如果我们有一定的破解能力,我们就能预测得到,下一次机器产生的随机数是哪个值。
在c++编程中,我们总要放一个随机种子,这个种子一般是当前时间,这样我们可以看到每次调用的随机数工厂产生的数值是不一样的。如果我们把随机数种子设定为一个特定的数,那么产生的随机数也是固定的。这样有一个好处,就是方便调试,因为调试的时候肯定不希望每次运行的结果都不一样。
#include<iostream> #include<ctime> #include <cstdlib> using namespace std; int main() { srand(time(0));//time(0)返回当前时间传到srand里面做随机种子 int x=rand(); }
但是在真正的计算中我们是希望随机数尽可能真的是随机出来的。所以又两种方法
1用更好的随机方法。算法没有最好的方法,就像排序算法一样,只有适合某种情形。
2用物理硬件:原子衰减检测。电路中量子力学噪声
0先告诉一个惊人的事实
c++ rand() 产生的随机数在[0,RAND_MAX]之间的一个整数.这是一个均匀分布.如果我们希望产出[a,b]之间的随机数通常会这么处理
(rand()%(b-a+1))+a
这种算法导致不是所以的值都是等概率出现的。只有当(b-a+1)可以整除RAND_MAX+1时才可以.假设RAND_MAX为32767那么生成[0
32766]的时候0的概率是其他值出现概率的两倍.一个解决的办法就是先成[0,1]之间的一个值,在放缩到[a,b]区间上.
double v=(double)rand()/RAND_MAX;
result=(int)(V*(b-a))+a;//这里一个书中给的代码是(V*(b-a+1))+a,我认为是错的,因为如果v=1的时候产生的值是b+1,如果我错了请务必告诉我
1介绍一个常用的分布,
如果我们希望以高斯分布的概率产生随机值,让更多的值不要偏离中心太多,那么该怎么做?
一个简单的方法(其实不简单)用randf()产生[0,1]之间的实数随机数,这个randf要自己编程,然后做BOX-Muller变换,这样可以产生两个随机数(买一赠一),不知道那个鸟变换没关系,我也不知道.
float x1,x2,w,y1,y2; do { x1=2.0*randf()-1.0; x2=2.0*randf()-1.0; w=x1*x1+x2*x2; }while(w>=1.0); w=sqrt((-2.0*log(w))/w); y1=x1*w; y2=x2*w;
那么问题来了。如何产生其他的分布?这个要用到中心极限定理。读者可以自己看看资料
2介绍几个不能用于加密的随机数产生算法
之所以说不能用于加密,是应用这种随机数可能使信息被破解的可能性大。
a线性同余生成器
x_(n+1)=(a*x_(n)+b)%m
其中x_(n+1)就是新产生的随机数,x_(n)是之前的数.n是零的话那个就是随机种子吧!a,b是一个参数,m是一个2的次方数(这样便于取余).vb6中这个算法的参数是m=2^24,a=16598013,b=12820163.
b截断线性同余生成器
先用a算法产生一个随机数,然后计算floor[x_(n+1)/k]。k是2的乘方把这个数返回。
当然还有其他的方法,线性反馈移位寄存器算法,逆同余生成器,滞后斐波那契生成器,元胞自动机,线性回归生成器,马特赛旋转法,well算法。
3可用于加密的随机数
blum blum shub算法。isacc,isacc+。这些都是算法,需要者自行百度。
/dev/random
这个是linux上的一个随机源,他基于系统熵返回一个随机数,可以看成一个真正的随机数.因为产生随机数需要系统收集信息,在系统没有足够信息的时候会造成阻塞。
微软的CryptGenRandom
这个也可是被视为真正的随机数,虽然未开源。