我的问题是:rand()%N被认为非常糟糕,而整数算术的使用被认为是优越的,但我看不出两者之间的区别.
人们总是提到:
> rand()%N中的低位不是随机的,
> rand()%N是非常可预测的,
>您可以将它用于游戏,但不能用于加密
有人可以解释这些问题是否属于这种情况以及如何看待?
低位的非随机性的想法应该使我所展示的两种情况的PE不同,但实际情况并非如此.
我想像我一样的人总是会避免使用rand()或rand()%N,因为我们总是被教导它非常糟糕.我很想知道c rand()%N生成的“错误”随机整数有效.这也是Ryan Reich在How to generate a random integer number from within a range年回答的后续行动.
说实话,那里的解释听起来很有说服力;尽管如此,我还以为我试一试.所以,我以非常天真的方式比较分布.我为不同数量的样本和域运行两个随机生成器.我没有看到计算密度而不是直方图的重点,所以我只计算直方图,只是通过观察,我会说它们看起来都一样均匀.关于提出的另一点,关于实际的随机性(尽管是均匀分布的).我 – 再次天真地计算这些运行的置换熵,对于两个样本集都是相同的,这告诉我们两者之间关于事件排序没有区别.
所以,出于很多目的,在我看来rand()%N会很好,我们怎么能看到它们的缺陷呢?
在这里,我向您展示了一种非常简单,低效且不太优雅(但我认为正确)的计算这些样本的方法,并将直方图与排列熵一起得到.
对于不同数量的样本,我在{5,10,25,50,100}中显示了域(0,i)和i的图:
我想在代码中没什么可看的,所以我会留下C和matlab代码用于复制目的.
- #include <stdlib.h>
- #include <stdio.h>
- #include <time.h>
- int main(int argc,char *argv[]){
- unsigned long max = atoi(argv[2]);
- int samples=atoi(argv[3]);
- srand(time(NULL));
- if(atoi(argv[1])==1){
- for(int i=0;i<samples;++i)
- printf("%ld\n",rand()%(max+1));
- }else{
- for(int i=0;i<samples;++i){
- unsigned long
- num_bins = (unsigned long) max + 1,num_rand = (unsigned long) RAND_MAX + 1,bin_size = num_rand / num_bins,defect = num_rand % num_bins;
- long x;
- do {
- x = rand();
- }
- while (num_rand - defect <= (unsigned long)x);
- printf("%ld\n",x/bin_size);
- }
- }
- return 0;
- }
这里是Matlab代码来绘制这个并计算PE(我从中获取的排列的递归:https://www.mathworks.com/matlabcentral/answers/308255-how-to-generate-all-possible-permutations-without-using-the-function-perms-randperm):
- system('gcc randomTest.c -o randomTest.exe;');
- max = 100;
- samples = max*10000;
- trials = 200;
- system(['./randomTest.exe 1 ' num2str(max) ' ' num2str(samples) ' > file1'])
- system(['./randomTest.exe 2 ' num2str(max) ' ' num2str(samples) ' > file2'])
- a1=load('file1');
- a2=load('file2');
- uni = figure(1);
- title(['Samples: ' num2str(samples)])
- subplot(1,3,1)
- h1 = histogram(a1,max+1);
- title('rand%(max+1)')
- subplot(1,2)
- h2 = histogram(a2,max+1);
- title('Integer arithmetic')
- as=[a1,a2];
- ns=3:8;
- H = nan(numel(ns),size(as,2));
- for op=1:size(as,2)
- x = as(:,op);
- for n=ns
- sequenceOcurrence = zeros(1,factorial(n));
- sequences = myperms(1:n);
- sequencesArrayIdx = sum(sequences.*10.^(size(sequences,2)-1:-1:0),2);
- for i=1:numel(x)-n
- [~,sequenceOrder] = sort(x(i:i+n-1));
- out = sequenceOrder'*10.^(numel(sequenceOrder)-1:-1:0).';
- sequenceOcurrence(sequencesArrayIdx == out) = sequenceOcurrence(sequencesArrayIdx == out) + 1;
- end
- chunks = length(x) - n + 1;
- ps = sequenceOcurrence/chunks;
- hh = sum(ps(logical(ps)).*log2(ps(logical(ps))));
- H(n,op) = hh/log2(factorial(n));
- end
- end
- subplot(1,3)
- plot(ns,H(ns,:),'--*','linewidth',2)
- ylabel('PE')
- xlabel('Sequence length')
- filename = ['all_' num2str(max) '_' num2str(samples) ];
- export_fig(filename)
解决方法
如果N是RAND_MAX的75%,则分布的底部三分之一的值是前三分之二的值的两倍(因为这是额外值映射到的位置)
rand()的质量取决于您所使用的系统的实现.我相信有些系统的实现很差,OS Xs手册页声明rand已经过时了. Debian手册页说明如下:
Linux C Library中的rand()和srand()版本使用相同的版本随机数生成器随机(3)和srandom(3),所以低阶比特应该与高阶比特一样随机.但是,老年人rand()实现,以及不同的当前实现系统中,低阶位的随机性要小于订单位.请勿在应用程序中使用此功能便携式,需要良好的随机性. (改为使用随机(3).)