如何生成随机数生成器序列

如何确定一列数是否随机? | 问答 | 问答 | 果壳网 科技有意思
如何确定一列数是否随机?
比如我想输出一列0~9之间的随机数算法1输出:...我认为这个输出并不随机,这列数的分布距离均一分布偏离太远算法2输出:...我认为这个输出也不随机,因为两个1之间的距离的分布距离泊松分布太远算法3输出:370774...我认为这个输出不随机,因为但是这种评价不够机械,比如算法3的输出,如果我看不出来这种递推关系那我很可能就会认为它是随机的。有没有一种机械的方法来确定一列数是不是随机的呢?
+ 加入我的果篮
科学松鼠会成员,信息学硕士生
我觉得LZ要搞清楚一件事情:随机性和“一个数列”其实是矛盾的。LZ的问题可以有两个方面的思考,一个是关于随机性,一个是关于数列的复杂程度。下面我简单叙述一下这两种思考。---------------------首先是有关随机性的思考---------------------首先,“一个随机的数列”是什么意思?某个给定的数列,不可能是随机的。想像一下,我们拿这个数列抛硬币,抛出来的结果是给定的,与“随机”的行为差很远。如果是要谈随机性的话,起码要是一个数列的概率分布才可以。那么,真随机就很好定义了:每个数列出现概率都一样的概率分布。但在现实生活中,真随机是否存在还是不太确定的。一般我们生成的,都是伪随机数。一般来说,伪随机数程序会在外界拿到一个随机的“种子”,然后从这个种子开始生成随机数列。这样看的话,给定外部种子的概率分布,这个伪随机数程序的结果实际上是一个数列的概率分布。这样我们就可以下定义了。伪随机的一个可操作的定义在这里:简单来说,给定一个可计算的序列的概率分布,如果没有程序可以(在一定的时间空间限制下)有效地将它与真随机序列对应的概率分布区分开来,那么这个序列就是(相对于对应的时间空间限制下的)伪随机序列。这个区分的程序我们一般叫distinguisher。一般我们希望计算序列的程序所需的时间空间限制远远低于distinguisher的限制,这样才能比较省时间,因为运算的大头一般也还不是在随机数生成上。现在有很多随机性测试,其实这些测试都可以视为distinguisher,而且是复杂度相当低的。在上面的定义中,一个很重要的思想是:因为所有利用随机序列来做某件事情的过程,都可以视为以这个随机序列为输入的一个程序,而得出的结果服从输入序列的概率分布经过程序处理后得出的概率分布。如果某个伪随机分布处理后得到的结果分布与真随机分布得到的结果非常接近,那么我们就可以将其视为真随机,因为只有结果是重要的嘛。只问结果,不问本质;只看关系,不看细节。这是搞数学的人希望厘清概念的时候常用的做法。学过一点密码学的同学应该知道,distinguisher 是攻击方用的,我们当然重视它的成本,希望这个成本越高越好。一般的攻击者都只有有限资源,如果是多项式时间的distinguisher的话,增加密钥长度一般没多大效果,所以我们希望不存在多项式时间的distinguisher。所以,在伪随机序列的讨论中,一般这个时间空间限制取为多项式时间。而在这个情况下,伪随机数存在当且仅当存在,而这是密码学里一个极其重要的未解问题,因为它关系到完全安全的公钥密码体系的存在性。大数乘法一般被认为是单向陷门,但其实没有证据。所以说,(多项式时间)伪随机数是否存在,其实也是不知道的。歪一下楼,distinguisher在密码中是怎么用来攻击的呢?直观地说,如果一个密码体系生成的数据越接近随机,那么就越难找到规律,因为看起来就像是随机数嘛。然后,如果对于某个密码体系,我们能构建一个distinguisher,将这个密码体系的输出与随机数据分开的话,就说明我们找到了某种规律,相当于破解有希望了。一般这种攻击可以让大家知道某个系统用的是什么密码体系,还可能可以排除某些密钥,减少暴力破解所需的时间。扯远了,回到随机性。既然不知道伪随机数是否存在,那么当然也不存在一个(多项式时间内的)程序能判断某个伪随机数生成器是否真的伪随机。所以,基本上我们用到现在的伪随机数生成器,都是靠蒙的,不能证明它们真的是伪随机。不过既然结果还凑合,在没有其它办法的情况下也就先用着了。---------------------然后是有关复杂度的思考---------------------但如果我们坚持不考虑数列的概率分布,坚持“一个数列”的原则,那么LZ的疑问又到底是什么呢?LZ列举了几个数列,然后列举了它们的规律。但是,这些数列的复杂程度很显然是不一样的。最后一个显然比第一个复杂,但我们如何界定这种复杂性呢?这种复杂性与“随机”又有什么关系呢?我们来想一下,当我们说“一个随机的数列”的时候,我们到底在说什么。如果一个数列很有规律,看着前几项就可以猜出后面的项的话,那么显然这个数列“不随机”。“一个随机的数列”,应该是无论我们给多少项,接下来的一项都很难猜出来。如果这些数列都是一些程序生成出来的话,我们会觉得,越复杂的程序,生成的数列看起来就越随机。那么,对于一个有限的数列,我们可以定义它的“随机性”为生成它所需要的程序的最短长度。如果一个数列只需要一个非常短的程序就能生成的话,它看起来就很“不随机”;反之,如果一个数列需要一个非常长的程序,甚至是一个跟数列本身差不多长的程序才能生成的话,它看上去就很“随机”。我们说一个数列是“随机”的,当且仅当它比能生成它的最短的程序还要短。在信息学中,这被称为。这个概念可以适当地推广到无限序列上。很不幸,它是不可计算的。Kolmogorov复杂度有些很诡异的性质。如果随机取一个无限序列的话,它是Kolmogorov随机的概率是1。但有一个叫Chaitin不完备性定理的东西却说,对于任意(可有限生成)的包含皮亚诺公理的公理系统(以及程序描述的语言)来说,存在一个常数L,使得我们不能举出一个Kolmogorov复杂度大于L的数列s,并形式地证明这一点。 也就是说,随便抓一个都是随机,但是就是证明不了……显然这个定理的证明方式与哥德尔不完备性定理的很像,都是某种诡异的自指……---------------------最后是免责声明---------------------其实这方面我也不是很熟,不是做这个的,道听途说……要认真钻研的话还是要去看书啊……
软件工程师,应用数学专业
所谓“随机”,要求只有一个:无法预测。计算机无法生成真正的随机数,使用诸如C语言rand()函数获得的都是伪随机数。生成随机数听起来很简单,但实际上涉及密码学,安全的随机数生成算法都可以保证知道前面N个数也无法预测下一个是什么,或者计算上不可能(计算规模太大)。所以,对于你来说,这样一串用伪随机数生成算法生成的序列就是随机的,因为你无法预测。先跑一下题说两个事:(1)生成随机数是密码学里面一个重要领域,很多加密算法的安全性依赖于伪随机数生成算法,所以它是现代信息学的基石,这些理论技术每天都在保障你的通讯安全。(2)任何加密算法,其安全性依赖的是密钥的保密而不是算法的保密,才是真正的安全。所以,常用的加密算法本身对大众是公开的,算法所需的密钥才是保密的。主流的伪随机数生成算法也是公开算法保护密钥的方式来确保安全性。伪随机数生成算法都包含一个你从外部无法得知的“种子”,可能是一个数。只要生成者保密这个种子,他生成出来的随机数序列就无法预测。但是,如果你通过某种途径得知了这个种子,你就可以根据其算法,预测之后每个随机数——欧漏,对于你来说,已经不是随机数了。所以,你还认为“随机”和“非随机”有绝对的区别吗?随机和不随机,取决于你,而不是生成序列的人。所以,任意给你一条数列,如果你可以通过自己过往经验,发现其中的规律,那对于你来说它就不是随机的,否则就是随机的。最后回到你的话题,机器如何判断一串数是否随机?取决于程序。你可以将很多种预测算法实现成程序,让机械去匹配预测,只要有一个匹配,那数列对机械/你来说就不是随机的。实际上这也是我们每天都接触的技术——压缩,数据压缩的本质就是预测,不过那扯远了。
要证明不随机,本质上只有一个做法,那就是预言下一次输出多少即使你获取了大量样本也没法看出到底是不是随机的如果不能获取算法那几乎是无法判断的
定性地说,那就是信息的“熵”越大越随机。可是熵的原始定义是出现概率的负对数,直接应用过来就意味着“从无穷多可能的数列中随机抽一个抽中此数列的概率”的负对数,然而这样的概率怎么能计算呢?况且其实它就是零概率(从无穷多中取1);那换一种方式,更接近通常理解的,就是把“上一位数字为X”时“这一位数字是Y”的条件概率作为定义数列信息熵的基石,但是同样也没法说清这个概率究竟该怎么算。说到底,信息熵的定义只在理想情况下(比如码元之间相互独立且每个码元出现概率为已知)才可计算,否则只是个理论上的东西,没法计算。
有一种随机的定义,如果输出一个二进制串所需要的二进制指令长度不比这个二进制串本身短,这个二进制串就是随机的你可以关注一下蔡汀(Chaitin)的工作
MT4专家,PYTHON工程师,程序员
如何判断?基础:大量生成定长M的数,然后根据1、没有重复2、统计各个数字的出现次数,基本一致3、统计N(N=2,3,...,M/2)排列的情况,没有明显的重复4、........单一的一个数,没有什么随机不随机
私立樱才学园学生会入会积极分子
算法3输出的数字其实是有规律而且循环的→_→(10)3,381,167,729,1011……
邪恶之王 大毒舌 欢乐
理论上说对于一个真正的随机输出,你得到的任何一组数都是随机的,如果你认为他不是,哪怕他看起来是,那是你的错觉。hiahiahia.
某审计学校的计算机学生
把π或者e,或者任何一个无理数写出来,这一列数组成的数列算不算随机呢 ,它的确可以计算,但是确实没有规律啊
我感觉DFT是个好办法我还听说过 可以观察连续出现相同数字的次数多数情况下如果一个“随机”数列是伪造的 那么连续出现同一个数的情况比真的随机序列要少
已有的结果分布无法说明是否真正随机,就好比.。。。。。。这个数列,如果这个数列的定义为:掷硬币,正面为9,反面为0,那么不管多少个9相连,我们也肯定人为这是个随机的事件,至于已经存在的数列,这只不过是记录随机事件的历史,这个历史在大量的样本情况下应该遵循概率为50%,但是谁能给出大量的确切含义呢?所以是否真随机,不是看分布,而是看驱动该分布生成事件本身。该事件对结果的影响关联性如果强,则事件本身随机性弱,如果关联弱,则事件本身随机性就强,直至纯正的随机事件。比较有代表性的就是量子相关性的验证。。。请有关牛逼人士来细说不妨。
生物学博士在读
不是游程检验吗?本来我觉得楼主问的是一个很简单的问题,但是楼上都跑题了,讨论伪随机数的生成……
化工工程师
能不能这样:第一步:考虑有限数列先定义它的子集,然后考虑含有元素个数相同但没有相同元素的那些子集(例如a_{1}, a_{3}, a_{4}, … 与 a_{2}, a_{5}, a_{6},考察这些子集之间的相关性。如果相关性约接近正态分布,则可以认为其约可能是随机数列。(对于真正的随机数列,任意子集(包含不同元素的)之间的相关性显然是0)。第二步,推广到无限数列具体怎么推广就要靠大神了。
科学艺术者
随机数本身指的就不是一个固定的数列。但即使把一个“无规律的数列”叫随机数,也不是那么容易明确简而言之,看看这列数字有规律没,没规律就是随机数,有规律就不是。至于这个规律是什么,各人有个人的想法
哪有什么随机数,真正随机的只是生成某个数的算法与初始条件,有了算法与初始条件“随机数"不就变成可预测的了。
有限数列就不多说了,必有“通项公式” x1,x2,x3,x4..........xn 必然有n次多项式的通项公式; 无限的数列,我们永远无法证明它没有通项公式。 因为,无限数列无论我们取前多少位都能找到其通项公式。 楼主的那个更简单,每个数都是一位,那么他必然有通项, 通项就是,我们把此无限数列排成一个小于1的实数A 则 xi=A的第i位。 相比整数序列的集合来说,实数的集合是更高阶的无穷大 相比实数的集合,函数的集合是更高阶的无穷大。 换句话就是说,一个数列可以找到无数个通项公式,但一个通项公式只能生成一个数列 1,2,3```````这个序列可以找到无数种通项公式对应 ai=i ai=isin2πi ai=i+tanπi 但反过来一个通项公式只能找到一个数列。
对于任何一列数字,总是能够构建出(或许规则会很复杂,但存在)一条规则使得这列数字符合这条规则。
后回答问题,你也可以用以下帐号直接登录
(C)2013果壳网&京ICP备号-2&京公网安备已有天涯账号?
这里是所提的问题,您需要登录才能参与回答。
"天涯问答"是天涯社区旗下的问题分享平台。在这里您可以提问,回答感兴趣的问题,分享知识和经历,无论您在何时何地上线都可以访问,此平台完全免费,而且注册非常简单。
用线性同余法生成随机数序列的公式是什么?
用线性同余法生成随机数序列的公式是什么?
09-10-16 & 发布
#include &iostream.h&int f(); int Y1(); int Y2(); void main(){ int Y,i,r,t=0;     float a,b,d;AA: cout && &请输入难度(1或2):&;   cin && Y;if ( Y!=1 && Y!=2 )  { cout && &输入难度错误,重新输入!& &&
   goto AA; }BB: cout && &请输入运算类型(+,-,*,/):& ;    cin &&  if ( p!='+' && p!='-' && p!='*' && p!='/' )  { cout && &输入运算符错误,重新输入!& &&    goto BB;}//出10道题,每题10分for( i=1; i&=10; i++ )  { l3: if( Y==1 ){ a=Y1(); b=Y1(); }        if( Y==2 ){ a=Y2(); b=Y2(); }        if (p=='-' )          if ( a&b ) goto  l3;          //使被减数大于减数       if ( p=='/' )        if ( int(a/b) != (a/b) ) goto l3; //只做结果为整数的除法       cout && a && p && b && '=';   cin &&    switch ( p )    { case '+':  r = a+b;      case '-':  r = a-b;   case '*':  r = a*b;   case '/':  r = a/b;    
 }    if ( r==d ){      cout && &算对了,加10分,加油!& &&      t = t+10; }    else cout && &算错了,继续努力!& &&  }   cout && &你的成绩是:& && t && &分& &&}int f(){  static  int  r;   r = ( 25173*r+13849 ) % 65536;  }int Y1(){  do  { rand = f();  }while ( rand&0 || rand&10 );  }int Y2(){  do  { rand = f();  }while ( rand&10 || rand&=
请登录后再发表评论!
随机数每次调用的结果并不一样,你在同一个环境里你会发现第一次运行rnd(X),第二次运行虽然每次结果不一样,但是每个参数的某次结果都是固定的。比如你那个rnd(-1),每次第一次调用它结果都是固定的。这个算法(你所说的表达式)因编译器/解释器而异,一般为了真实达到随机效果都要开启计数,也就是在算法里加上时钟的值这个参数。用法也是不同的。GCC编译器和微软的编译器采用的就是不同的表达式。 至于负数,谁知道你手头那个编译器是怎么算的。
请登录后再发表评论!labview创建随机数的多种方法之一 
随机数多用于仿真过程中,LABVIEW作为一种编程语言,特别适合于仿真过程,因此,与常规语言不同,直接提供了多种创建随机数和随机数序列的方法。但是由于侧重点的不同,LABVIEW在多个函数选板中,提供了多种不同的函数,下面大概总结一下。
一、伪随机数发生器
在LABVIEW数值函数选板中,提供了一个随机数发生器函数,返回一个0-1之间的伪随机数。常规语言中都提供了类似的RAND函数,LV的帮助文件中对该函数没有细节方面的描述。
该函数与常规语言的RAND函数也有不同之处,常规语言的RAND函数一般可以自行选择种子,对于相同的种子,执行相同的算法,因此会返回相同的随机数。
默认的种子通常是系统时钟,估计LABVIEW也是如此。但是LABVIEW函数内部可能是在首次调用时使用系统时间作为种子,再次调用时可能内部使用了前一次的结果作为种子,因为接近相同时刻函数不会返回相同的随机数,如下图所示。
二、任意范围的随机数发生器
LV提供的随机数发生器返回的0-1之间的双精度随机数,实际应用中经常需要的是指定范围的随机数,这可以通过简单的线性运算实现,如下图所示。
三、均匀白噪声
均匀白噪声是一组离散的随机数,随机数的平均值为0,随机数序列的预期标准偏差是幅值的0.577倍。
& = E{x} = 0
通过LV的随机数发生器,可以很容易生成这样的序列,满足均匀白噪声的标准,如下图所示:
LV在信号生成函数选板中专门提供了几种随机数序列发生器,包括均匀白噪声、周期性随机噪声、高斯噪声、二项式分布的噪声等等,如下图所示。
&信号生成模板的几种噪声生成函数使用方法十分类似,下面以均匀白噪声为例,重点分析一下它的用法。
均匀白噪声生成信号函数使用非常简单,但是特别要注意种子和初始化输入端子的用法,该函数可以设置种子值,为-1时表示使用内部随机种子。内部随机种子调用的是基本的随机数发生器函数,由于基本的随机数发生器函数使用内部时钟作为种子,所以使用默认随机数种子时,均匀白噪声实质上是系统时钟相关的。
初始化端子如果为TRUE,每次调用时都可以更新种子值,如果为FALSE,则连续调用时使用前一次生成的种子值,看一下该函数的程序框图。
在给定种子时,因为遵循同样的算法,所以相同种子值返回的随机数序列是相同的,如下图所示:
三、正态分布随机数序列
所谓正态分布随机数序列,就是要求随机数序列必须满足平均值和标准方差的要求,并呈正态分布。
伪随机序列的期望均值&和期望标准偏差是
& = E{x} = 0
= [E{x & &}2]1/2 = s
伪随机序列产生约290个采样后才会出现重复。
下面创建一个正态分布随机数序列,并计算它的均值和标准方差。
信号生成选板中还提供了其它几种噪声函数,这里就不再详细讨论了,下一篇文章中介绍波形函数选板中的几种随机数发生器,以及概率函数选板中的随机数发生器,这些随机数发生器都是以信号噪声函数为基础的,在此基础上进一步实用化。
旗下网站: |
与非门科技(北京)有限公司 All Rights Reserved.
京ICP证:070212号 北京市公安局备案编号: 京ICP备:号伪随机数与伪随机数生成器
计算机是确定性的机器,因此它无法直接生成真正的随机数,而浑沌系统的随机数生成速度又比较慢,在许多情况下不适合作为快速的(伪)随机数库函数算法。快速的伪随机数生成算法中最著名的要数linear-congruential method(线性同余法),也就是:
Xn+1&=(a Xn&+ b&)%
c&&&&&&&&&&&&&// %&就是C/C++&中的MOD(同余)运算符
这种方法可以从一个种子X0&= seed开始,连续生成任意长的伪随机数序列Xn&。它的运算过程极其简单,并且如果令c
= 2m,其中m为Xn的字长,则连MOD运算都直接省掉了——&Xn+1&≥2m&时高位自动溢出而被截除。用这种办法生成的伪随机数序列,在给定范围和精度内确实满足均匀分布的要求,但是并非连续分布,因为计算机存放数据的精度不是无限!正是由于最小数据间隙的存在,该序列将会以一个相当长的周期循环。
更为重要的是,上述方法为代表的伪随机数生成器,其生成的数字序列并非拥有不可辨别的模式,相反,它们的规律都极其容易由少量数据反推得到。这里有两种具体情况,一类是数据加密中要应用到伪随机数,则此种“易于反推出规律的”伪随机数生成器很不合适;另一类是科学计算中用到的伪随机数,这时并不要求一定得掩盖住其内在规律,但是却有另外的要求:伪随机数的内在规律不能与所研究问题的自然规律相似,并且在必要的时候需要使用高精度的方法减小“最小数据间隙”。
之所以称其为“线性同余法”,是因为Xn+1&=(a Xn&+
b&)% c生成的伪随机数实际上是分布在一条经MOD运算截断的直线上,其近似具有“随机性”的核心也就是这个同余运算。但是如果将相继的一对数(x=X2i&,y=X2i+1)作为一对二维坐标确定平面上的一个点,则在伪随机数数列上的一个小区段内显然会连续出现几对数,它们各自确定的点在平面上沿一直线排列,这也就是文章开头我所提到的现象。其中直线的方程——
设该小区段为Xp,Xp+1,Xp+2,……Xp+
则相应的点对为(Xp,Xp+1),(Xp+2,Xp+3),……
直线y = Ax + B =(aX + b)MOD
c =(aX MOD c)+ b
而(aX MOD c)= aX - Floor[ aX /c ]·c&,
∵根据算法要求,c相比于aX是一个较大的常数,
∴在一个小区段内总有Floor [ aX /c ]≡Floor [ aXp&/c
用常数P记Floor [ aXp&/c ]&,则直线方程可写为:
y = Ax + B = aX + b - cP&,
此方程当且仅当&cP&≤&aXp&<&aXp+
m&<&cP+c时成立。
这种二维平面上的规律性严重影响到我的模拟计算,因此不得不反复调用randomize()函数来初始化伪随机数生成器——即使是使用两个独立的伪随机数生成器也不能避免类似的规律性。但是randomize()函数是利用系统时钟作为种子实现初始化的,这导致“不断初始化”的办法存在严重的问题:
其一,读取系统时钟的函数需要访问CPU-RAM总线以外的慢速设备,因此执行时间相当慢,会严重影响高性能计算的速度。当然,外围时钟可以利用现代操作系统的虚拟时钟设备在CPU内部仿真实现,这部分的缓解了此问题。
其二,系统时钟的计时精度并不高,但是今日的计算机“CPU-高速缓存”子系统运行速度非常高,以至于CPU在系统时钟计时精度的最小间隙(微秒级)之内就可以完成上千次操作。如果运行速度很快,因而非常频繁地读取系统时钟来初始化的话,可能会导致相继的几次读取获得完全相同的时钟值,换句话说,就是连续多次使用同一个种子来做初始化,那么显然会获得完全相同的伪随机数数值。
其三,以线性同余法为代表的简单伪随机数生成算法,最初生成的几个数受初始化种子的影响很大,所以随机性都不好,一般需要舍弃伪随机数序列的前几个值——这种不均匀性问题在上述高速运行的情况下特别严重!因为在非常频繁地做初始化时,每次采用的种子即使不完全相同,也是紧密相邻的。如果舍弃数列中的前几个数,却又会增加运算量、降低效率。
总之,频繁利用系统时间初始化这一方法在高速运算时的效果相当差。
但是从好的方面看,只要研究者对自己处理的科学计算问题思路明确、图像清晰,一般来说总是有办法避免伪随机数序列的内在规律与所研究问题的自然规律相似;同时只要略微施加一些编程上的技巧,就能有效地以存储空间换运行时间,避免反复调用系统时间做初始化的动作。例如对于上述例子,可以开辟一个二维数组T[2][max](max≠2n),然后:
randomize() ;
for (i=0 ; i& i++)
&&&&&&&&&&&T [1][ i ] = Random(Range_We_Need) ;
&&&&&&&&&&&/*&这里的Random函数根据具体情况返回需要的数据类型&*/
randomize() ;
for (i=0 ; i& i++)
&&&&&&&&&&&T [2][ i ] = Random(Range_We_Need) ;
依据此算法存放一组伪随机的二维坐标数据对,而后在调用时按列读取数据对(T[1][i]&,T[2][i]),在“max”不大时(例如5000对于双精度浮点数组),整个数组(78.125KB)可以完全缓存在CPU的L2
cache中,这样就能迅速的生成和读取一系列的坐标数据对。同时,由于T[1][i]&与T[2][i]并非相继生成一对随机数,它们之间的联系因为两次非密集的randomize()调用而几乎完全不相关。如果所需的数据对非常多以至于超过max对,也可以根据情况再次生成这么多对数据后取用,但是最好不要随意加大数组的最大大小。
上面是对于特殊用法的一个解决方案特例,其它各种各样的情况也可以类似的具体问题具体对待,比如一维随机行走问题就完全可以直接使用连续的“线性同余”伪随机数序列,最多不过需要在走过相当长的一段时间之后重新初始化一下伪随机数生成器。事实上,如果科学计算时所需的大量随机数是各自独立使用的,那么大多可以直接连续应用线性同余法产生的序列而无需顾虑太多,间或插入一个“初始化”操作。但是,线性同余法只能确保在“各自独立使用”的一维情况下,随机数数列上每一个小区段内局部没有明显的相关规律,二维及其以上的高维就需要具体分析——所谓“二维或高维”,也就是前述那种需要连续产生随机向量的情况。
为什么要过一段时间插入一个初始化操作呢?
除非加上一些程序外的数据——例如系统时间,否则任何伪随机数生成器一定是循环的,只是循环周期的长短不同。因为伪随机数生成器是一个固定的运算程序,并且前一个输出是下一个运算的输入,但计算机的数值储存状态是有限的,因此必然会在循环到某一时刻产生与前面相同的结果,从此开始重复前面的一个循环。要延长周期,最简单的办法就是过一些循环后重新拿系统时间来做一下初始化;当然还可组合两个以上的伪随机数生成器一起工作,有许多种组合方式,例如:用第一个生成器产生h个随机数,用第二个随机数生成器随机扰乱它们的顺序后输出;或者可以用第一个随机数生成器产生一个seed和一个整数h,而第二个生成器以seed为种子连续产生h个随机数……
混沌动力学系统产生的随机数
对于一般的科学研究来说,只要保证伪随机数的内在规律不与所研究的自然规律相似,并且在所需数据精度下呈现“准连续的均匀分布”即可,而对“由少量数据反推生成规律”这种反向工程的困难程度不作限制。有时甚至还需要一种简单清晰的生成规律,以便确认这种规律是否与所研究的自然规律相似。
但是,在数据加密的时候,往往对这种反向工程极为担心,因此需要设计一种难于被反推出的生成规律。由大质数组合出巨大合数的乘法对反向工程来说相当困难,但是它需要用特殊的、巨大的数据结构来存放数据和进行运算,因此不适合用于扩展成为快速产生伪随机数的算法。
而混沌动力学系统演化过程中生成伪随机数的办法却相当合适。选取一组好的非线性方程组,只要对程序中所用非线性方程的几个常数最初的值保密,并且根据自身输出的伪随机数,每一些循环之后调用系统时间来悄悄更改这些常数,那么哪怕整个算法都公开给全世界,也几乎不可能被反向工程找出规律(也就是找出那些常数值的变化规律)。只要在运行一段时间之后才开始对外发布这些伪随机数序列,那么即使是暴力穷举法也没有可能正向破解出其内在规律。算法如下:
+++++++++++++++++++++++++++++++++++++++++++++++++++++
本算法未经密码安全性检验,使用者须自行承担可能的安全性风险
+++++++++++++++++++++++++++++++++++++++++++++++++++++
FirstFill( Constant[ n ] ) ;&&&&&&&&&//&生成几个常数的初值,这需要硬件随机数
/* Constant[ ]&数组除第一个外存放的是各个常数的值,均为整数,并且
sizeof( Constant[ n ] )&≥&安全所需的加密强度,例如512bits
do {&&&&&Refill( Constant[ n ], SYSTIME, RandomOutput( Constant[ n ] ) ) ;
/*&读取系统时间,并产生几个伪随机数,
然后以这几个数据混合运算出新的Constant[ n ]&值&*/
for (count=Constant[0] ; count&0 ; count - - )
&&&&&&&&&&&&&&&&&RandomOutput( Constant[ n ] ) ;&&&&&&&&&&&&&&&//&连续输出伪随机数
&&&&&&&&&&
&&&&&&&&&&&Ask( ENDorNOT ) ;
} until ( ENDorNOT==Yes ) ;
&&&&&&&&&&
这就是利用混沌动力学系统的初值敏感性进行“反反向工程”的伪随机数产生算法,初值上的微小差异将在一小段时间之后导致非常巨大的分歧,所以“由运行一段时间之后才开始发布的伪随机数序列反推初值”的做法几乎不可能实现;至于如何应付暴力穷举法的正向破解——只要数组Constant[n]&的总长度足够长,并且严密保护好其中任何一个初值都不被窃取,那么穷举所需时间的数学期望也是不可思议的漫长。
困难的是,如何对这些即时生成的伪随机数作归一化校正,使任意一小段很短的伪随机数序列也能呈现均匀分布。另外,虽然混沌动力学系统所产生的伪随机数其内在规律不容易与一般应用中的规律相混淆,(即使同样是研究混沌动力学系统,只要模型略有差异就不会有问题,)但是万一有所混淆,查找问题根源就变得极为困难。这里我提供一个权宜之计:收集伪随机数子程序的输出,待收集到足够多的值以后对它们进行FFT,可以尝试一维、二维……任何一种你觉得必要的傅里叶变换;若发现变换出的结果有显著的规律性,那么立即再次收集一批不同的输出数据,重复刚才的测试过程数次。假如类似的规律始终存在,那么就说明此伪随机数子程序有明显的规律性,不宜使用;另一方面,如果你没有发现任何显著的规律,也不表明这个子程序就很优秀——只是你暂时还没发现缺陷罢了。
如何使伪随机数的内在规律变得更加隐蔽?如何使它看起来(并且用起来)更像是一个真正的随机数而不是可预测的结果?这些问题,不仅在科学计算领域被经常提出,并且更为迫切的出现在电子商务、机密通讯等涉及到高度保密的信息传递的领域。这是因为现今比较流行的加密算法几乎都基于一些来自于随机数的密钥,而如果采用伪随机数的话,其内禀规律一旦被别有用心的人发现,那么就有可能推算出密钥,进而破译相应的密文!上述的混沌动力系统可以产生基本符合要求的伪随机数序列,但是更符合需要的随机数应该是来自于硬件设备的真随机数……
硬件随机数生成器
伪随机数并非是“坏随机数”,只是某些情况下为稳妥起见我们不得不使用“真随机数”,产生真随机数的办法必须依赖硬件,其原理不外乎于量子力学和混沌动力系统。量子力学的随机现象迄今没有更深层的规律性,因此利用放射源衰变等过程得到的随机数序列肯定是真正随机的,在经过归一化校正后,便可以作为优秀的随机数序列发布了。但是,混沌动力系统不是“伪随机”的确定性系统吗?它怎么能产生“真随机数”呢?
我们说纯软件的混沌动力学系统伪随机数生成器产生的是伪随机数,这是因为现有软件运行在完全确定性的计算机上,并且计算机可以存放的数值虽然离散、但却准确无误——例如因为有限位二进制存储方式离散的缘故不能准确存放实数X=3.00000……,可是却能准确存放例如X=2.9999983
E+00这样一个完全确定的近似值。那么,在各种条件和变化过程都完全确定的计算机中,产生的随机数当然是可以预测的“伪随机数”。
现实世界中的硬件设备就不同了,例如有些硬件利用的是电子元件温度的随机波动经电子学放大而产生随机数,理论上它应该满足一个“热传导-流体力学”复合的非线性动力学方程组,但实际上并没有可能利用这样的方程组来预测随机数产生情况:
首先,我们无法精确确定该模型的初始条件,许多物理量最多只能测到4~6位有效数字。这一方面是因为测量工具自身精度的局限性;另一方面是因为客观世界的微观涨落使这些初始值快速小幅变化着;甚至在足够小的微观尺度上还会撞上量子的“不确定性原理”。种种原因都导致很难在客观世界中同时测出一系列初值的精确值,相比之下,我们可以在计算机中的模型上指定任意多个足够准确(高达8~15位有效数字)的初始值,并强制令其为“同一时刻”的值。
其次,计算机模拟过程中很容易限定环境条件(在8~15位有效数字的精度上)保持稳定,而在现实世界中这是不可能的!以PCI卡形式的随机数生成器为例,机箱内空气的湿度、温度和速度矢量分布上的微小波动,都可能显著影响到它的散热情况,又如果把它们都考虑为扩展模型的变量,那又会大大增加模型的初始条件数目,使“同时测出一系列初值的精确值”变得更加不可能。
可见,利用现实世界中测不准初值的混沌动力学系统,因为它的初值敏感性,我们也可以获得几乎完全不能预测的随机数序列。对于基于量子力学的硬件产生的无限随机数序列,预测它是不可能事件;而基于混沌动力系统的硬件产生的无限随机数序列,预测它是零概率事件,亦即说,对于可以预见的未来的任何一种应用,都可以放心的视为“不可能事件”!总之,我们把依赖量子力学或者混沌动力系统的硬件随机数生成器统称为“真正的”随机数生成器。
一个长半衰期的放射源(如T1/2=30年的Cs-137)加上一个盖格计数器,辅以有效的防护设备和计算机数据接口卡,还要再加上一个调试好参数的归一化校正程序,就可以组成一套不错的硬件随机数生成器,并且是基于量子力学的完全不可预测的随机数产生装置。但随着放射源的嬗变和仪器设备的慢慢老化,这个归一化校正程序需要每过一段时间就校正一次参数,这倒不是什么大问题;真正的大问题在于,它产生随机数的效率太低了!为保证足够的测量精度,探测器的增益不可以太大,这样该装置的随机数输出带宽受放射源辐射强度的限制,可能只有每秒几个bit甚至几十秒才有一个bit&!
(电阻或者二极管中)电子热运动的Johnson噪声是量子效应,根据这个原理产生随机数的硬件装置可以更快地输出随机数,例如ComScire或者Tundra公司的一些设备,可以以20
kb/s的带宽输出质量优异的真随机数。Intel RNG的带宽为75kb/s,并且几乎不需要花费额外的费用,因为这个装置所需的硬件是Intel
82802 Firmware Hub(也就是BIOS设备)中的标准配件。从2003年起,威盛电子(VIA)在其CPU中嵌入了PadLock
RNG模块,由于采用CPU内核级别的设计和生产工艺,它的访问速度很快,并且号称能以800~1600 kb/s的速率生成真随机数——折合成单精度浮点数却也不过25~50
kHz&。VIA PadLock RNG的技术原理是联合使用一组四个集体管震荡器,其随机性本源还是来自Johnson噪声。
正因为硬件随机数生成器产生的数字完全是随机的,即使是设计和使用它的人也无法找到这些真随机数的生成规律,所以用一个软件来精确的校正其分布变得相当困难,必须使用大量统计数据获得经验校正函数,而且还不能保持非常好的校正精度,这一点对加密应用来说问题不大,但是对于科学计算而言就会大大降低计算结果的精度。
硬件随机数生成器最大的缺点在于:它们都太慢了!即使是VIA PadLock RNG的25~50 kHz单精度浮点数产生速率,也远远跟不上当前主流x86系统的2~5GFLOPS
/ CPU的浮点计算速度:单CPU工作时差不多每十万次浮点操作才能等候到一个单精度随机数,用于计算密集型的科学研究工作显然不够。
说到这里,就不得不提一些半硬件半软件的解决方案,它们不需要专门的硬件设备,可以跨平台的应用于几乎任何一种计算机上,比Intel或者VIA的RNG还容易获得;但它们又不是完全的软件伪随机数生成器,而是至少近似不可预测的(半真半伪的)随机数来源,从本质上来说,它们是混沌动力系统硬件随机数生成器的一类:
这些生成器中,有些捕捉键盘、鼠标、硬盘驱动器的动作以及外设中断信号(DMA等),并由此作为随机数的来源;有些则把互联网上的不确定行为收集起来作为随机数来源,例如本机的网络信号流量波动情况;还有一些会从系统硬盘上任意选定的声音、图像、动画文件中提取随机信号,或者从声卡、调制解调器之类的AD/DA转换器中提取背景噪音。这些不确定行为的最根本来源是个人或者人类社会的活动,而人或者人类社会是非线性的耗散系统,显然可以认为上述随机数生成方法都是基于混沌动力系统的。
被采样的行为虽然看起来将会随机发生,但其实这种随机性却无法证明,如果这些物理动作是静止的(比如说服务器的鼠标和键盘可能根本就没连上)或者是简单重复的,就可能生成一系列低质量的随机数,由此导致随机数硬件源的质量远远低于设计者在最理想条件下的预期值。不过,虽然质量较低且不稳定,这些硬件却比那些直接利用放射源计数或者电子热运动等现象制造的专用硬件廉价、常见得多,并且已经在系统层或者驱动程序层实现了通用的随机数池设备,从使用者的角度来看更接近软件解决方案——无论是它的易用性还是实现方式。
它们当中最著名的一种,就是Linux 1.3.30版以上内核开始在系统层提供的随机数池虚拟设备“/dev/random”。“/dev/random”设备驱动程序收集来自其它硬件的动作信息:鼠标、键盘、磁盘驱动器、各种接口卡等等,将这些未经校正的随机信息填充到一个通用的“(信息)熵池”中,然后在需要访问“/dev/random”设备时提供合适的统计学函数校正和转换。当然,它收集信息的速率也很慢,甚至比那些基于量子效应的专门硬件还慢!不过一般而言质量确实也能接近基于量子效应的硬件随机数生成器。
由于运作速度慢,“/dev/random”的“熵池”在频繁读取时将很快枯竭,因此我们不应该把这个设备当作快速获取大量高质量随机数的来源,而应该从另一个相关的虚拟设备“/dev/urandom”中获取。“/dev/urandom”设备以“/dev/random”中的随机数做种子,利用MD5算法生成纯软件的伪随机数,其效果显然比简单的线性同余法高许多,相应的速度也会低一些。调用这两个虚拟设备的方法很简单,本文最后的附录中给出了相应的C99程序实例。
为了高速的产生大量(伪)随机数,我们不得不使用纯软件的伪随机数生成器,而任何纯软件随机数生成器本身是不能自发生成信息熵的,它必须有一个来自硬件的输入——也就是一个来自“熵源”的数据。按通常的算法描述,就是要先对伪随机数生成器进行初始化,例如用系统时间作种子来初始化,这一操作在32位的C99标准中会输入32bits的信息熵,此后每一次调用系统时间“重新初始化”理论上都会引入32bits信息熵。这里有两点需要注意:
第一,两次初始化之间,该伪随机数生成器输出的序列总共只有32bits的信息熵,而无论到底输出了多少bit的信息!当然,并不妨碍在许多情况下正常的使用这些低熵的数据。
第二,如果非常频繁的调用系统时间“重新初始化”,则前后两次获取的系统时间数值之间的相关性太大,就不会重新引入32bits信息熵了。因此有必要适当降低调用系统时间的频率,或者使用其它更快的硬件随机数生成器作为“熵源”。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:53056次
积分:1057
积分:1057
排名:第17564名
原创:22篇
转载:203篇
评论:40条
(1)(1)(4)(7)(3)(2)(9)(19)(11)(9)(7)(1)(6)(5)(40)(31)(17)(7)(29)(5)(5)(8)(1)

我要回帖

更多关于 如何生成随机数 的文章

 

随机推荐