简体   繁体   English

rand() 每次给出几乎相同的数字

[英]rand() gives almost the same number every time

I'm learning C and I want to generate a number between 0 and 6400. This is the code I came up with:我正在学习 C,我想生成一个 0 到 6400 之间的数字。这是我想出的代码:

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

int main()
{
    srand(time(0));
    int i = (rand() % 6401);
    printf("Random number between 0 and 6400: %d\n", i);
    return 0;
}

When I compile and run this code from the command line I get some very weird results:当我从命令行编译并运行这段代码时,我得到了一些非常奇怪的结果:

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6295

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6321

K:\C\Labo\Oefeningen 2019>

The numbers are all different but I would expect a somewhat even distribution between 0 and 6400. The weird thing is that I was using the same function without problems an hour ago?这些数字都不同,但我希望在 0 到 6400 之间有一个稍微均匀的分布。奇怪的是,我在一小时前使用相同的 function 没有问题? (I was using it to generate smaller numbers before.) I'm certain it's something really stupid that I'm missing but I've been stuck for an hour now. (我以前用它来生成较小的数字。)我确定我错过了一些非常愚蠢的东西,但我现在已经被困了一个小时。

EDIT: I know It will give the same value when you run the code within the same second.编辑:我知道当您在同一秒内运行代码时它会给出相同的值。 I waited multiple seconds (10-20) between executions and I still get the same result?我在执行之间等待了几秒钟(10-20),但我仍然得到相同的结果? The values are rarely the same, they are just very very very similar 100 % of the time.这些值很少相同,它们只是 100% 的时间非常非常非常相似。 How do I get around this?我该如何解决这个问题?

time() has resolution of 1 second. time()的分辨率为 1 秒。 So your program will generate at different value only after half a second has passed on average.因此,您的程序仅在平均经过半秒后才会生成不同的值。

If your compiler supports C11, you can use a higher-resolution function, timespec_get() .如果您的编译器支持 C11,则可以使用更高分辨率的 function、 timespec_get() Your srand(time(0));你的srand(time(0)); will then transform to the following:然后将转换为以下内容:

struct timespec ts;
timespec_get(&ts, TIME_UTC);
srand(ts.tv_nsec);

Here ts.tv_nsec is the nanosecond part of the time stamp, whose resolution should be good enough for your purpose.这里ts.tv_nsec是时间戳的纳秒部分,其分辨率应该足以满足您的目的。

If your compiler doesn't support C11, you can still have a better source of random seed than time() , with about a millisecond resolution (actual resolution is given by CLOCKS_PER_SEC macro): the clock() function.如果您的编译器不支持 C11,您仍然可以获得比time()更好的随机种子源,分辨率约为毫秒(实际分辨率由CLOCKS_PER_SEC宏给出): clock() function。 Then your seeding code will be然后你的播种代码将是

srand(clock());

Note though that it may actually be a bad source of entropy, especially if your OS is not busy, so that the program would run at somewhat predictable pace.请注意,它实际上可能是一个不好的熵源,尤其是在您的操作系统不忙的情况下,因此程序将以某种可预测的速度运行。 It's because beginning of the clock() 's era is related to the program's execution, not to real time.这是因为clock()时代的开始与程序的执行有关,而不是与实时有关。 It might be better to eg use a sum of clock() and time(0) to get more unpredictable value:例如,最好使用clock()time(0)的总和来获得更多不可预测的值:

srand(time(0)+clock());

Computers doesn't really generate random numbers.计算机并不会真正生成随机数。 Thus, when you execute your code twice on the same second it returns the same value.因此,当您在同一秒内执行两次代码时,它会返回相同的值。 In order to have better result you could add the value of getpid() in srand.为了获得更好的结果,您可以在 srand 中添加 getpid() 的值。

Keep in mind that this still not real random.请记住,这仍然不是真正的随机。

If your rand is busted, you can try one of the xorshift pseudo-random number generators.如果您的rand被破坏,您可以尝试其中一种xorshift伪随机数生成器。 They are not perfect but the resulting implementation is very short.它们并不完美,但最终的实现非常短。 It could be enough for your own use.自己用可能就够了。

Here is an implementation example: I used this one as reference.这是一个实现示例:我使用这个作为参考。

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

uint64_t    xorshift64s(uint64_t seed)
{
    static uint64_t i = 1;

    if (seed != 0)
        i = seed;
    i ^= i >> 12;
    i ^= i << 25;
    i ^= i >> 27;
    i *= 0x2545f4914f6cdd1d;
    return (i >> 32);
}


int main()
{
    srand(time(0));
    int i = (rand() % 6401);
    printf("rand    : Random number between 0 and 6400: %d\n", i);
    xorshift64s(time(0));
    int j = (xorshift64s(0) % 6401);
    printf("xorshift: Random number between 0 and 6400: %d\n", j);
    return 0;
}

If anyone else runs into this problem I think I found a workaround.如果其他人遇到这个问题,我想我找到了解决方法。 I know this isn't a perfect solution but it's the only one that worked for me.我知道这不是一个完美的解决方案,但它是唯一对我有用的解决方案。 I think the random number generator used in my compiler doesn't like similar seeds at all.我认为我的编译器中使用的随机数生成器根本不喜欢类似的种子。 With this code snippet it actually generates somewhat acceptable semi-random numbers:使用此代码片段,它实际上会生成一些可接受的半随机数:

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

int main()
{
    srand((unsigned int)time(0) * 100000000);
    int i = (rand() % 6401);
    printf("Random number between 0 and 6400: %d\n", i);
    return 0;
}

This is where I got my garbage can compiler from btw: http://tdm-gcc.tdragon.net/download这是我从 btw 获得垃圾箱编译器的地方: http://tdm-gcc.tdragon.net/download

The numbers generated by rand aren't truly random, they're generated with a formula. rand生成的数字并不是真正随机的,它们是使用公式生成的。 That's why seeding is both possible and necessary.这就是为什么播种是可能的和必要的。 Depending on the formula used, there can be a high correlation between the seed and the first few random numbers.根据使用的公式,种子和前几个随机数之间可能存在高度相关性。

The cures are to use a better formula (something not rand ), use a more random seed, or waste a few random numbers just after seeding.解决方法是使用更好的公式(不是rand ),使用更随机的种子,或者在播种后浪费一些随机数。

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

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