构造随机函数的目标是建造性能优良的随机函数,该函数能够生成性能优良的随机数组。
基本方案:
组织一些数据,处理好后备用,每次函数调用输出一个数据,数据用完了再次组织数据处理好继续下去。函数也要设置初值,但初值不是种子,它能起到控制作用。
基本原理:
理论基础是热力学第二定律——熵增加原理,当我们以多种方式影响数组的序列时,数组将向着更加混乱的方向发展而不可能相反。首先组成数组的元素是均匀的每种元素地位是均等的,如果有缺员或某元素过多或过少那都不行,都不能生成优良的随机数。其次是改变这些元素的排列,数组初始排列是什么样都没有关系的,这可以利用现有的随机函数来实现,这里随机排序是重要的工具,随机排序就是让数组内的元素位置随机的交换,一般可以用循环来完成,例如长度为N的数组,用一个循环变量 i,从头到尾的循环,另外随机的在N中选择一个位置,用这个位置的元素和第 i个元素进行交换,这样循环一次每个元素都被交换了,交换完成后新的顺序建立了,生成了新的数组。从N中选择位置的操作可以用某个随机函数来完成,也可以拼凑一些随机性较强的变数来完成。一遍随机排序不理想可以进行多遍,一般借助于优秀的随机函数一遍就够了,这样子就生成了一个长度为N的数组。道理是这样实际操作却复杂多了,且看下面:
将组成随机数组的元素准备好,并利用随机排序等数学手段使其分布均匀,使其趋近于自然状态下的均匀分布,然后再一个一个输出这些数据。这里称组成数组的所有元素组成的小数组为单元数组,例如常用的数组可能是字节数组,字数组或双字数组,这里主要讨论字节数组,因为别的数组都可用它来组合。字节数组的单元数组就是0-255共计256个元素,现在的问题是,需要多少素材利用随机排序才能达到目的,我们以单元数组来组成素材,这样容易在数量上达到均匀,显然单元数组用少了是不行的,举例说明例如就用两个单元数组,经过随机排序后可以输出函数值了,但是这样的结果是不可能连续输出三个一样的元素,这就和现实偏离了,通过数据试验和检测可以得出结论用大于512个单元数组即可满足需要,再加上有效的随机排序就能够生成性能优良的数据了。使用其它随机函数的作用,只是参与数组序列顺序的排列,不影响任何元素的数值,作用只是洗牌对牌的数值无影响,试验表明普通随机函数都可胜任。
上面介绍了,以多个最小单元构建原始数组的方法,下面的方法是用现有随机函数的序列值放到字节数组中组成原始数组,一般常用的随机函数放在字节数组中分布都是很均匀的,实践证明数组长度太小也是不行的通过试验找出最小达标数组的长度,将数组长度大于此值就可以了,试验表明这个数值取10000即可,
这可比上面方法的数组小多了。有了数组打乱数组的排序方法也是随机排序和上面是一样的就不再赘述了。
下面给出应用后一种方法制作的随机函数实例(C语言)。
//定义随机函数和全局变量
unsigned char SJHS(void); //随机函数
unsigned char A_[10000+1]={0}; //数组
int B_1=0; //计数器
//随机函数的实体部分
unsigned char SJHS(void)
{
int i,QC=10000;
int n1=127;
unsigned char ch;
if(B_1==0)
{
for(i=0;i
{A_[i]=rand();} //生成原始数组
for(i=0;i //随机排序 更新数组
{
n1=rand()%(QC);
ch=A_[i];
A_[i]=A_[n1];
A_[n1]=ch;
}
B_1=QC-1;
QC++; //取材量逐渐增大,作用是使函数周期更大
}
else
{
B_1--;
}
return A_[B_1];
}
函数形式很简单,很容易用其它语言实现。函数利用了C语言的随机函数rand(),使用时可以利用其设置初值的函数srand(初值)来设置初始值。随机函数在这里只起到提供数组素材,和改变数组排序的作用,也可以用其它随机函数来完成,肯定效果会更好,这里也证实了即便使用最简单的rand()函数也能使本函数达到很好的效果,化腐朽为神奇。
本函数周期的问题,决定周期的因素有两个,储备数组取材和随机排序的激励方式,如果重复出现将产生本函数输出的重复,也就是周期现象。上例随机函数的周期是多少呢?在此我们的随机函数值都是放在字节数组中的,测算了一下其周期是5.222乘10的10次方,是个相当大的数字了,比较一下rand()函数的序列值如果放到字节数组中,其周期只有16M多,上面的周期几乎扩大了3万多倍,一般的应用是不会受周期的影响的。
下面是用本例函数生成10M字节数据的NIST检测结果。
近似熵检测ApproximateEntropy = 0.303526
块内频率测试BlockFrequency = 0.694508
累积和测试CumulativeSums = 0.462014 , 0.710217
离散傅立叶变换测试FFT = 0.022555
频率测试Frequency = 0.418930
线性复杂度检测LinearComplexity = 0.650879
块内最长连续“1”测试 = 0.397033
非重叠模板匹配测试NonOverlappingTemplate [1] - [148]项 = 0.710217
重叠模板匹配测试OverlappingTemplate = 0.800998
随机偏移测试RandomExcursions八点 =
0.924882,0.876947,0.688437,0.498380,0.165862,0.379719,0.029511,0.173761
随机偏移变量测试RandomExcursionsVariant十八点 =
0.294932,0.408295,0.486860,0.633896,0.746212,0.572653,0.640780,0.993325,0.612019,0.270
751,0.228289,0.127769,0.159240,0.087272,0.061477,0.182087,0.377224,0.588332
二元矩阵秩测试Rank = 0.959887
游程测试Runs = 0.097216
串行测试Serial = 0.398658
全局通用统计测试Universal = 0.253360
这是第四次测试前三次也是全部合格。
本方法可以对任何现有随机函数进行改造,这里的例子是用了最简单的随机函数。若用性能优良的随机函数,随机性会更好,周期会更大。例如使用MT19937,若用多个随机函数来决定随机排序的位置,随机性会更大,周期会更长,更符合熵增加原理所说的用多种方式。
本函数和一般随机函数完全不同,它不是基于算式的,而是基于物理定律而生成随机数的。在加密程序中你可以用它直接生成密钥数组,在游戏程序中使变化更加突如其来等等,相信能有很好的应用。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2018-7-10 18:39
被sjdkx编辑
,原因: 丰富内容