c - rand 函数在每次运行时都给我相同的结果,即使我调用了 srand(time(NULL))

标签 c random

<分区>

我有一个问题,我想使用 rand() 来获得 0 到 6 之间的随机数,但每次运行它总是给我 4,即使我调用 srand (时间(NULL))

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

int main(void)
{
    srand(time(NULL));

    int rd = rand() % 7;

    printf("%d\n", rd);
    return (0);
}

每次运行的输出都是4

最佳答案

您的代码存在两个基本问题,它们结合在一起会产生您遇到的奇怪结果。

几乎任何人都会警告您有关 rand() 接口(interface)的使用。实际上,Mac OS 联机帮助页本身以警告开头:

$ man rand
NAME
     rand, srand, sranddev, rand_r -- bad random number generator

是的,这是一个糟糕的随机数生成器。糟糕的随机数生成器可能难以播种,还有其他问题。

但说到播种,这里还有另一个问题,可能讨论得较少但仍然很重要: Do not use time(NULL) to seed your random number generator .

链接的答案对此进行了更详细的介绍,但基本问题很简单:time(NULL) 的值很少更改(如果频繁以纳秒为单位),并且不会更改当它改变时很多。因此,您不仅依赖程序不经常运行(或至少每秒运行一次),而且还依赖随机数生成器从略有不同的种子中产生截然不同的值。也许一个好的随机数生成器可以做到这一点,但我们已经确定 rand() 是一个糟糕的随机数生成器。

好的,这很笼统。具体问题有点有趣,至少出于学术目的(学术,因为实际的解决方案总是“使用更好的随机数生成器用一个好的随机种子来播种它”)。这里的确切问题是您使用的是 rand() % 7

这是个问题,因为 Mac OS/FreeBSD 的 rand() 实现是将种子乘以 7 的倍数。因为该乘积是模 232(不是7的倍数),缓慢递增种子产生的第一个随机数的模7值最终会发生变化,但必须等到溢出量发生变化。

这是一个 link to the code .本质就在这三行:

    hi = *ctx / 127773;
    lo = *ctx % 127773;
    x = 16807 * lo - 2836 * hi;

根据评论,“计算 [s] x = (7^5 * x) mod (2^31 - 1) 而不会溢出 31 位。” x 是最终返回的值(模 232),也是下一个种子。 *ctx 是当前种子。

16807,正如评论所说,75,显然可以被 7 整除。而 2836 mod 7 是 1。所以根据模运算规则:

x mod 7 = (16807 * lo) mod 7 - (2836 * hi) mod 7
        =          0         -       hi mod 7   

该值仅取决于 hi,即 seed/127773。所以 hi 每 127773 个刻度变化一次。由于 time(NULL) 的结果以秒为单位,因此在 127773 秒内发生一次变化,大约一天半。因此,如果您每天运行一次程序,您会注意到第一个随机数有时与前一天相同,有时则少一个。但是你运行它的频率比这高得多,即使你在运行之间等待几秒钟,所以你每次都会看到相同的第一个随机数。最终它会下降,然后您会看到一系列 3 而不是 4。

关于c - rand 函数在每次运行时都给我相同的结果,即使我调用了 srand(time(NULL)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66808250/

相关文章:

python - 将 PCL 链接到 Cython C++ 模块

c - 内存泄漏 char* C程序

python - 随机数索引过去的输入 Python

python - Django - make_random_password 方法,它真的是随机的吗?

javascript - 延迟后自动播放随机HTML音频的Javascript函数

c++ - 随机循环终止条件是否明确定义?

c - 为什么函数指针可以带或不带运算符地址使用?

c - VDSO(7) 和 SYSCALL(2) 之间有什么关系?

c - 获取该行的每个字符,然后对其进行加密

javascript - Math.random() 返回值大于一?