如何使OSX的rand()无法进行光谱测试?

时间:2013-04-29 19:59:05

标签: c random prng

出于编程类的目的,我试图说明通常随标准C库一起出现的随机数生成器的弱点,特别是OSX附带的“坏随机生成器”rand()(quoth)手册页。)。

我写了一个简单的程序来测试我对光谱测试的理解:

#include <stdio.h>
#include <stdlib.h>

int main() {
  int i;
  int prev = rand();
  int new;

  for (i=0; i<100000; i++) {
    new = rand();
    printf("%d %d\n", prev, new);
    prev = new;
  }
  return 0;
}

但是当我绘制得到的散点图时,我得到的是:

Spectral test of OSX's rand()

我原本期望某些东西显示出更多结构,就像人们发现on Wikipedia一样。我在这里做错了吗?我应该绘制更多尺寸吗?

更新

根据pjs的建议,我放大了数字小于1e7的情节部分,这是我发现的:

Spectral test of OSX's rand() limited to numbers smaller than 1e7

我发现pjs显示完全相同的线条。它们似乎是垂直的,但这是不可能的,因为它意味着某些值被rand()“遗漏”了。当我sort -n数据时,我看到的是(样本):

571 9596797
572 9613604
575 9664025
578 9714446
580 9748060
581 9764867
584 9815288
586 9848902
587 9865709
590 9916130
592 9949744
127774 13971
127775 30778
127780 114813
127781 131620
127782 148427
127783 165234
127785 198848
127787 232462
127788 249269

换句话说,这些点位于几乎但不完全垂直的线条中。

2 个答案:

答案 0 :(得分:11)

线性同余发生器都受到George Marsaglia发现的问题的困扰。 “Marsaglia's Theorem”说k元组(长度为k的向量)将落在有限数量的超平面上。边界是m**(1/k),其中k是元组的大小,m是用于生成器模数的数字。因此,如果模数为(2**31 - 1)并且您正在查看3组,则3-d图将显示不超过(2**31 - 1)的立方根或大约1290个平面的点,从正确的方向看。

所有LCG都受Marsaglia定理的约束。一个“好的”在上限或接近上限执行,一个坏的下降远远超过上限。这就是光谱测试有效测量的结果,这就是你在维基百科链接中看到的 - 兰德,来自地狱的LCG,产生的三胞胎只有15架飞机。

Apple的碳库生成器使用16807作为其乘数,(2**31 - 1)作为其模数。正如LCG一样,它并不是那么糟糕。因此,你的情节没有表现出兰多的极端情况。但是,如果您想要质量合理的随机数,请不要使用LCG。

<强>附录

我已经完成了从Apple rand()函数中获得了十亿个数字,但只打印了两个值都小于200万的那些数字,即你的情节的左下角。果然,他们落在了线上。由于线条的密度,你只需要真正放大才能看到它。

老乔治是一个聪明的家伙!

Marsaglia at work

答案 1 :(得分:3)

假设坏rand是一个线性同余生成器,即它的形式为:

next = a * prev + b (mod RAND_MAX+1)

你可以只用几个术语来解决ab的等式。之后,您应该能够生成输出函数,使结构变得明显。