用“序列数交换法”产生真随机数组
2007-01-27 21:04
246 查看
用“序列数交换法”产生真随机数组
“序列数交换法”是将有规律的数组,通过任意交换数组的序列号,而形成随机数的方法。
理论根据是热力学第二定理的推论“熵增加原理”,在自然作用下,从有序到无序是不可逆过程。例如你整天洗纸牌,也不可能有一天发现是一顺的了。墨水滴到水盆里会逐渐扩散,如果你搅动则会加速扩散,再也没有机会聚成一滴了。
“序列数交换法”的物理模型可以是这样的。将有规律的数组,例如载体可以是大小一样颜色不同的小球,不同颜色代表不同的元素,放到一个滚筒里,滚动均匀,然后一个个拿出来排列,就得到了新次序下的随机数组。
现在我们用计算机来模拟这个过程。以ASCII码组成的数组为例(这在计算机是最基础的,以字节为单位), 我们的元素是 0 ~ 255 的数字,共有 256个。
例如造一个有2560个元素的随机数列:
1) 先做一个数值由零到255的循环数列,长度为2560(现在数组周期为256),
2) 随机抽取两的序号使它们的数值交换,
3) 使 2)进行足够多次,检测其效果,直到满意为止。
下面用 C++语言来实现。只写出关键部分。
#define NN 2560 //数组长度
unsigned int i;
unsigned char *str; //定义数组指针
unsigned char ch;
unsigned int n1=0;
str = new unsigned char[NN+1]; //借用内存
for(i=0;i<NN;i++) str[i]=i%256; //形成序列数组
srand(GetTickCount()); //用运行时间做随机种子
for(i=0;i<NN;i++)
{
n1=(rand()+i)%NN; //随机生成序号以便交换
if(n1==i) goto xia; //序号相同不处理
else
{
ch=str[n1]; //数值交换
str[n1]=str[i];
str[i]=ch;
}
xia: ;
}
delete [] str; //退还内存
以上程序,借助一个随机函数 rand() 来完成挑选交换目标序号的工作,rand() 实际也对应序号从0到NN-1的数组,只不过表现形式比较怪异,我们称此数组为“捡选数组”。此段程序将有序的数组str[]从头到尾处理了一遍。形象的说就是处理了一次或搅动了一次。如果选择的随机函数比较优秀,一次搅动,可以使数组具有随机数组的统计特性,如果用几个好的随机函数,多做几次可能效果更好。如果随机函数不好,多次也能达到目的。
试验证明随机函数在这里不是必需的。用开始形成的序列数组str[]取代rand()作为“捡选数组”,以后每次用上次生成的str[]数组作为“捡选数组”,这样经过许多遍处理后也可以形成真随机数组,过程比较缓慢,是个逐渐打乱次序的过程,可以观察到随着搅动次数的增加从序号小的地方开始逐步由规律排列到不规律排列,变成乱码后,又由有周期的乱码向无周期变化。这种自我激励的变化也从一个侧面印证了“熵增加原理”,说明不管用什么方法有序到无序是不可逆转的。但是使用随机函数可以大大加快进程,尤其是好的随机函数,差一些的效率要降低。随机函数只是个工具,真正起作用的是“熵增加原理”。上述正反馈式的自我激励处理过程,简称自激处理,还有其它用途,当借助随机函数的搅动进行到一定程度时,用此方式来扫尾,可以消除随机函数本身处理的痕迹,并可源源不断的产生新的真随机数组。
如何检测随机数质量。这里是根据随机数组的统计特性来检验它。方法众多仅举一例:
unsigned int n2=0;
for(i=0;i<NN;i++)
{
if(str[i]==(i%256)) n2++;
}
我们知道,元素在特定的位置有 256种可能,所以某元素出现的概率是1/256,元素总数2560乘1/256等于10,当n2接近10时即可,就是再继续搅动,n2将在10 附近震荡,说明均匀度已经饱和。对于真随机数组来说,再多搅性质是不会改变的,只是做无用功罢了。
真随机数组的一大特点是不能重复出现,现在如何保证呢。因为 1)使用了以时间为种子的随机函数,2)过程结束是靠判断自动完成的。由于系统是多任务系统,同样的运算需要的时间是不同的,这和计算机状态相关,而运行时间又和随机函数种子的数值相关,微小的差异就可以使结果不同,自动完成则搅动的次数就是不确定的,所以完成随机数组的建造过程是不可复现的。
真随机数组虽然用处很大,但是对普通加密真随机数并不一定便于应用,还是自己控制随机函数种子好些,只要你加入些不确定因素即可,你可以使用密码来控制种子的数值,而密码是运行后输入的,根本不出现在没有运行的程序里,这样对你来说数组是伪随机数组,而这个数组跟搅动的随机函数没有直接关系,但在破解者那里就是真随机数组了,这样的随机数组可以称为单向真随机数组吧,也是做不出来的。
“序列数交换法”是将有规律的数组,通过任意交换数组的序列号,而形成随机数的方法。
理论根据是热力学第二定理的推论“熵增加原理”,在自然作用下,从有序到无序是不可逆过程。例如你整天洗纸牌,也不可能有一天发现是一顺的了。墨水滴到水盆里会逐渐扩散,如果你搅动则会加速扩散,再也没有机会聚成一滴了。
“序列数交换法”的物理模型可以是这样的。将有规律的数组,例如载体可以是大小一样颜色不同的小球,不同颜色代表不同的元素,放到一个滚筒里,滚动均匀,然后一个个拿出来排列,就得到了新次序下的随机数组。
现在我们用计算机来模拟这个过程。以ASCII码组成的数组为例(这在计算机是最基础的,以字节为单位), 我们的元素是 0 ~ 255 的数字,共有 256个。
例如造一个有2560个元素的随机数列:
1) 先做一个数值由零到255的循环数列,长度为2560(现在数组周期为256),
2) 随机抽取两的序号使它们的数值交换,
3) 使 2)进行足够多次,检测其效果,直到满意为止。
下面用 C++语言来实现。只写出关键部分。
#define NN 2560 //数组长度
unsigned int i;
unsigned char *str; //定义数组指针
unsigned char ch;
unsigned int n1=0;
str = new unsigned char[NN+1]; //借用内存
for(i=0;i<NN;i++) str[i]=i%256; //形成序列数组
srand(GetTickCount()); //用运行时间做随机种子
for(i=0;i<NN;i++)
{
n1=(rand()+i)%NN; //随机生成序号以便交换
if(n1==i) goto xia; //序号相同不处理
else
{
ch=str[n1]; //数值交换
str[n1]=str[i];
str[i]=ch;
}
xia: ;
}
delete [] str; //退还内存
以上程序,借助一个随机函数 rand() 来完成挑选交换目标序号的工作,rand() 实际也对应序号从0到NN-1的数组,只不过表现形式比较怪异,我们称此数组为“捡选数组”。此段程序将有序的数组str[]从头到尾处理了一遍。形象的说就是处理了一次或搅动了一次。如果选择的随机函数比较优秀,一次搅动,可以使数组具有随机数组的统计特性,如果用几个好的随机函数,多做几次可能效果更好。如果随机函数不好,多次也能达到目的。
试验证明随机函数在这里不是必需的。用开始形成的序列数组str[]取代rand()作为“捡选数组”,以后每次用上次生成的str[]数组作为“捡选数组”,这样经过许多遍处理后也可以形成真随机数组,过程比较缓慢,是个逐渐打乱次序的过程,可以观察到随着搅动次数的增加从序号小的地方开始逐步由规律排列到不规律排列,变成乱码后,又由有周期的乱码向无周期变化。这种自我激励的变化也从一个侧面印证了“熵增加原理”,说明不管用什么方法有序到无序是不可逆转的。但是使用随机函数可以大大加快进程,尤其是好的随机函数,差一些的效率要降低。随机函数只是个工具,真正起作用的是“熵增加原理”。上述正反馈式的自我激励处理过程,简称自激处理,还有其它用途,当借助随机函数的搅动进行到一定程度时,用此方式来扫尾,可以消除随机函数本身处理的痕迹,并可源源不断的产生新的真随机数组。
如何检测随机数质量。这里是根据随机数组的统计特性来检验它。方法众多仅举一例:
unsigned int n2=0;
for(i=0;i<NN;i++)
{
if(str[i]==(i%256)) n2++;
}
我们知道,元素在特定的位置有 256种可能,所以某元素出现的概率是1/256,元素总数2560乘1/256等于10,当n2接近10时即可,就是再继续搅动,n2将在10 附近震荡,说明均匀度已经饱和。对于真随机数组来说,再多搅性质是不会改变的,只是做无用功罢了。
真随机数组的一大特点是不能重复出现,现在如何保证呢。因为 1)使用了以时间为种子的随机函数,2)过程结束是靠判断自动完成的。由于系统是多任务系统,同样的运算需要的时间是不同的,这和计算机状态相关,而运行时间又和随机函数种子的数值相关,微小的差异就可以使结果不同,自动完成则搅动的次数就是不确定的,所以完成随机数组的建造过程是不可复现的。
真随机数组虽然用处很大,但是对普通加密真随机数并不一定便于应用,还是自己控制随机函数种子好些,只要你加入些不确定因素即可,你可以使用密码来控制种子的数值,而密码是运行后输入的,根本不出现在没有运行的程序里,这样对你来说数组是伪随机数组,而这个数组跟搅动的随机函数没有直接关系,但在破解者那里就是真随机数组了,这样的随机数组可以称为单向真随机数组吧,也是做不出来的。
相关文章推荐
- 随机产生数组长度是80的序列
- 快速排序算法的C++实现及随机数组的产生方法
- 通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小(两数组的差最小)。
- 产生均匀随机排列数组
- 产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复
- 产生一个int数组,长度为100,并向其中随机插入1-100
- 面试题:产生一个长度为100的数组,为数组中的每一项随机填充1-100之间的数并且保证不重复
- 随机不重复序列的产生
- 产生随机的栈操作序列
- 产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复
- 面试题:产生一个长度为100的数组,为数组中的每一项随机填充1-100之间的数并且保证不重复
- 随机产生12个5到15之间的整数放入一维数组中,然后将这些数输出,每行输出4个数
- 产生一个int数组,长度为100,并向其中随机插入1-100,不重复
- 关于一道 产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复
- 1.将数组A中的内容和数组B中的内容进行交换。(数组一样大) 2.获取一个数二进制序列中所有的偶数位和奇数位,分别输出二进制序列。 3.将三个数按从大到小输出。 4.求两个数的最大公约数。
- 用Random_buffer产生随机序列
- 产生一个int数组,随机向数组中插入1-100的随机数且不能重复
- Javascript经典算法学习1:产生随机数组的辅助类
- 随机产生1到n的不重复序列
- 产生一个长度为100的int数组,并向其中随机插入1-100,不能重复