正文

[转贴]关于随机数生成2005-12-19 11:59:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/rickone/8553.html

分享到:

转自:http://www.gro.cn/dll.asp?url=3895/3895954.htm


很多学计算机的学生大学四年学下来连随机数是怎么产生的都弄不明白,更有甚者连随机函数怎么调用都搞不清楚,这不能不说是一种悲哀。嗯,现在让我们一起使这种悲哀成为历史吧^_^ 。首先我们要搞清楚一个概念,生成单个的随机数是没有意义的,我们所说的随机数生成,其实都是生成一个随机序列。鉴于人们通常对具体的做法比对分析要感兴趣,我会先给出一系列随机数生成算法,后面我会对这些算法和其它命题进行稍稍深入的讨论。
要找到真正的随机数来源很困难,象离子辐射事件的脉冲检测器,气体放电管和带泄露的电容,我们不可能给每台需要产生随机数的电脑配这么一套装置,况且这些东东产生的数值的随机性和精确性都有问题。所以我们只能考虑通过某种算法来产生随机数。算法都是确定的,因此我们无法产生真正统计随机的数值序列,但是,如果算法很好,所得的序列就可以通过许多随机性测试,这些数就是所谓的伪随机数了。
现在用得最广泛的伪随机数产生算法就是所谓的线性同余算法。其随机数序列{Xn}由方程:Xn+1 = ( aXn + c ) mod m得到,其中m>0称为模数,0≤ a <m称为乘数,0≤c <m称为增量,0≤X0<m称为初始值或种子,当m、a、c、X0都是整数时,通过这个方程就能产生一系列[0,m)范围内的整数了。很明显,对一个线性同余随机产生算法来说,最重要的是m、a、c的选择。我们希望产生的序列足够长,能包含[0,m)内所有的数,并且产生的数是随机的,最好能用32bit算术高效实现。于是乎为了有足够的空间产生足够长的队列,我们会使m足够大;为了使序列足够完整,足够象随机序列,我们会发现当m是素数,c为0时就可以使序列的周期(即序列不重复的长度)对于一定的a达到m-1;要能用32bit算术高效实现,我们的m当然不能超过32bit,幸好刚好有一个满足上述条件的很方便的素数2^31-1给我们用,于是产生函数就变成了Xn+1 = ( aXn) mod ( 2^31 – 1 )。在超过20亿个a的可选取值中,只有很少的几个可以满足上述所有条件,其中之一就是a = 7^5 = 16807。于是我们可以实现如下(完整的代码code栏目中提供打包下载,下同):
    unsigned myrand()
    {
        return (seed = (seed * 10807L) & 0x7fffffffL);
    }
这种产生器得到了广泛的使用和比其它产生器都彻底的测验,其产生的随机数有在分布上有很好的特性,但是却不具备良好的不可预测性。所以我们在使用时往往会以系统时钟(模m)或系统时钟与随机数的和(模m)作为种子来重新启动序列,这也是现在绝大多数随机数产生器的做法。
另一种产生伪随机数序列的方法就是使用加密逻辑,通过加密算法的雪崩效应,输入的每一位改变就会造成输出的巨大改变,并且假如密钥被妥善保存的话从序列中前面的数推出后面的数在计算上是不可行的,于是我们可以使用一个简单的累加器来作为输入,得到的随机序列可以直接使用(当然也可以把系统时间等等因素考虑进去作为输入来产生更随机的序列,不过这通常是没有必要的),这种方法常常用来产生会话密钥或是现时。具体采用的加密逻辑和运算方式有很多,这里就不一一介绍了,大家感兴趣可以找本密码学的书来看看。
在密码学领域里比较流行的一种产生安全的伪随机数的方法是BBS产生器,它用其研制者的名字命名(Blum Blum Shub,不是我们经常灌水的那个BBS),它的密码编码强度据说具有最强的公开证明。首先,我们找两个大素数p和q,要求它们被4除都余3,令n = p×q,再选择一个随机数s,使s与n互素,然后我们通过如下算法产生一系列比特Bi:
X0 = (s^2)mod n,
for i = 1 to ∞
Xi = (Xi-1^2)mod n
Bi = Xi mod 2
每次迭代都只取出最低位的bit。可以看出BBS产生随机数的过程非常复杂,运算量很大,嗯,这就是为安全性付出的代价-_-b。《密码编码学——加密方法的C与C++实现》一书所附光盘有其完整实现代码,大家可以到电子工业出版社下载区把代码下下来看看。

阅读(19097) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册