简体   繁体   English

为什么我在第一次迭代中从 rand() function 中得到几乎相同的数字?

[英]Why do I get nearly the same number out of the rand() function in the first iteration?

in my C99-programme I want to use pseudo-random numbers between 0 an 1. Unfortunatly, my programme always generates a first number that is almost identical.在我的 C99 程序中,我想使用介于 0 和 1 之间的伪随机数。不幸的是,我的程序总是生成几乎相同的第一个数字。 It just steps up ever so slightly every time I rerun my programme.每次我重新运行我的程序时,它都会稍微增加一点。

This is the relevant part of my programme:这是我程序的相关部分:

srand(time(NULL));  
for(int i = 0; i < 10; i++){
    float a = (float)rand()/RAND_MAX;
    printf("%f\n",a);

And here are the results of two Iterations with a time difference of below 10 seconds:以下是时间差低于 10 秒的两次迭代的结果:

0.717103
0.357464
0.903628
0.271930
0.327478
0.917489
0.231215
0.026307
0.135259
0.290941

0.717221
0.330531
0.237708
0.151682
0.318986
0.201876
0.936884
0.209277
0.324705
0.311334

I tried to generate completely different numbers no matter how many I computed before, but the first is alway close to the same.无论我之前计算了多少,我都试图生成完全不同的数字,但第一个总是接近相同。

Patterns like this are typically caused by low-quality linear congruential pseudorandom number generators .像这样的模式通常是由低质量的线性同余伪随机数生成器引起的。 Each random number is computed as X new = ( aX old + c ) mod m .每个随机数的计算公式为X new = ( aX old + c ) mod m When you seed this with a number of seconds, the change between the first value generated after seeding at one time and the first value generated after seeding one second later is a modulo m .当您以秒为单位播种时,一次播种后生成的第一个值与一秒后播种后生成的第一个值之间的变化m

If you are using a Unix system (such as macOS or Linux), you can use srandom andrandom instead.如果你使用的是 Unix 系统(比如 macOS 或 Linux),你可以使用srandomrandom代替。

The problem appears to be that your system's rand() implementation is sensitive to the fact that successive return values from time() don't differ by much — that is, aren't supplying much entropy.问题似乎是您的系统的rand()实现对time()的连续返回值相差不大这一事实很敏感——也就是说,没有提供太多的熵。

I tried your code on my machine and got remarkably similar results.我在我的机器上试过你的代码,得到了非常相似的结果。

You need to provide a bit more entropy, to "mix things up".你需要提供更多的熵来“混淆”。

One technique I like to use (at least, on Unix-like systems) is to add the process ID into the seed, since the pid will be different each time.我喜欢使用的一种技术(至少,在类 Unix 系统上)是将进程 ID 添加到种子中,因为每次 pid 都会不同。 Usually I've done it like this:通常我是这样做的:

srand(time(NULL) + getpid());

This is a good way to make sure your program generates different results even if you invoke it twice in the same second.这是确保您的程序生成不同结果的好方法,即使您在同一秒内调用它两次也是如此。

Unfortunately, this wasn't enough to make a difference with your code on my machine, and I suspect it won't help on yours, either.不幸的是,这不足以改变您在我机器上的代码,而且我怀疑它对您的机器也无济于事。 The problem is that (especially on a non-loaded system) the process ID typically just increments by 1 or 2 each time also, and it's adding in to the same low-order bits of time 's return value which also aren't changing by much.问题是(特别是在未加载的系统上)进程 ID 通常每次也只增加 1 或 2,并且它添加到相同的低位time的返回值中,这也没有改变很多。 (And the high order bits of the pid don't change at all, and are being added to the high-order bits of the time of day, which also aren't changing.) (并且 pid 的高阶位根本没有改变,并且被添加到一天中时间的高阶位,这也没有改变。)

On my system, I got decent results with在我的系统上,我得到了不错的结果

srand(time(NULL) ^ (getpid() << 16));

and I suggest you try this.我建议你试试这个。

If that doesn't help, you'll want to use either a significantly better entropy source, or a significantly better pseudorandom number generator.如果这没有帮助,您将需要使用明显更好的熵源或明显更好的伪随机数生成器。

These days, virtually all Unix-like systems have a good source of entropy accessible via the special file /dev/random .现在,几乎所有类 Unix 系统都有一个很好的熵源,可以通过特殊文件/dev/random访问。 So a superior way of seeding a pseudorandom number generator is with code like this:因此,为伪随机数生成器提供种子的一种更好的方法是使用如下代码:

FILE *fp = fopen("/dev/random", "rb");
if(fp != NULL) {
    unsigned int seed;
    fread(&seed, sizeof(seed), 1, fp);
    srand(seed);
    fclose(fp);
}

(For a production program, obviously you'd have to decide what to do if the fopen call failed.) (对于生产程序,显然您必须决定如果fopen调用失败该怎么办。)

Eric Postpischil's answer mentions random , a significantly better PRNG available on most systems. Eric Postpischil 的回答提到了random ,这是一种在大多数系统上都可用的明显更好的 PRNG。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM