生成分布均匀的随机数

时间:2011-11-28 05:32:12

标签: c linux random

我有一套455件物品,我随机选择最多160件物品,并更换。首先,我使用srand()播种,然后使用rand()选择每个数字。我观察到,在我最多160件物品的选择中,我倾向于看到至少10件物品被选中不止一次。这似乎表明随机数不均匀分布。

有没有办法让分布更均匀的随机数?

7 个答案:

答案 0 :(得分:5)

你对结果的直觉是错误的。如果数字是真正随机的并且在0到455之间均匀分布,那么在160个数字的集合中存在至少10个重复的概率实际上非常高(实际上它是虚拟确定性)。非正式地,这被称为“生日悖论”,虽然它实际上并不是一个悖论。

此图表显示当您从一组455中选择160个独立的相同分布值时出现不同数量的重复项的概率。正如您所看到的,实际上您最有可能获得22个重复值,几乎有没有机会你得到少于10或超过35。

enter image description here

答案 1 :(得分:3)

听起来你生成随机数的底层实现工作得很好。似乎问题在于您从总人口中选择项目的方式。这篇关于simple random samples的维基百科文章描述了选择子集与替换无替换之间的区别。你想要后者。

想象一下,你有一个装有许多独特编号球的盒子。你正在做的是随机选择一个球,但是在写下你所选择的球之后,将球重新放回盒子然后再选择。这允许进行重复选择的可能性。但是,你想要的是在选择球之后消除这种可能性。为此,您必须根据随机生成的数字更改用于进行随机选择的机制。可以找到一个很好的例子here

答案 2 :(得分:1)

尝试使用arc4random()中的stdlib.h。它具有比rand()更好的伪随机数生成算法,并且它不需要您设置初始种子。

答案 3 :(得分:1)

gnu gsl library中实现了一组适当的随机数生成器。 你可以选择各种各样的井tested random number generators。对于严重的计算,不要使用rand()。 在您的情况下,我将使用给定输入集中的gsl_ran_sample。 这看起来像这样:

#include <stdlib.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

#define N 455
#define K 160

int main(int argc, char **argv)
{
    double arr[N];
    double randarr[K];
    gsl_rng *r = NULL;
    const gsl_rng_type *T;
    int seed = 31456;   // intial seed of the random number generator 
    int i;

//        gsl_rng_env_setup(); // if you want to set different random number generators etc.. or set external seeds
    T = gsl_rng_ranlxs2;
    r = gsl_rng_alloc(T);
    gsl_rng_set(r, seed);

    for (i = 0; i < N; i++) {
        arr[i] = i;
    }

//      gsl_ran_choose(r, randarr, K, arr, N, sizeof(double)); // without replacement
//      in case of choose: you will need to call gsl_ran_shuffle(r, randarr, K, sizeof(double)) if you want to randomize the order.  

    gsl_ran_sample(r, randarr, K, arr, N, sizeof(double));  // with replacement
    fprintf(stdout, "Picked array elements:\n");

    for (i = 0; i < K; i++) {
        fprintf(stdout, "%f\n", randarr[i]);
    }
    gsl_rng_free(r);
    return 0;
}

如果你有正确安装的gsl。用

编译
gcc -Wall main.c  `gsl-config --cflags --libs`

答案 4 :(得分:0)

创建一个从0到454的455个整数数组,随机地将其洗牌,然后使用其前160个数字作为原始455个项目数组的索引。这将保证选择的唯一性。

我应该以有趣的方式添加a little pic from Dilbert解释概率。

维基百科上还有一个很好的article on statistical randomness

答案 5 :(得分:0)

好吧,没有看到你的代码很难分辨出什么是错的,但是你总是可以使用/dev/random设备来绘制随机数。只需将其作为文件打开并从中读取即可。

但是,你仍然可能会重复。只是过滤掉它们。

答案 6 :(得分:0)

虽然我确定你可以使用其他伪随机数生成器,但除此之外。你的期望是不现实的。使用我有理由相信*的随机数生成器,我发现你需要从一组455中选择少于100个项目,以期期望重复的项目少于10个。如果唯一性很重要,那么它很容易实现;如果随机性很重要,那么你就好了。我可以保证你的随机数分布很好。

*我在原始随机数上使用了各种变换来从一组中挑选。如果生成器出现问题,则不同的转换会显示不同的偏差。他们没有,所以我很满意发电机足够接近随机的问题。