gpt4 book ai didi

c++ - 第一个随机数始终相同

转载 作者:行者123 更新时间:2023-12-03 07:56:31 26 4
gpt4 key购买 nike

我正在尝试编写一个简单的程序。我听说C++中存在比rand()更好的现有函数(生成随机数)。我说的是 #include <random> 中的类(class)。我的程序目标是生成随机数。

这是我的代码:

int randomSpawn()
{
unsigned seed = time(NULL);
std::default_random_engine rng(seed);
std::uniform_int_distribution<int> d(1, LENGHT);

srand(time(NULL));

std::cout << d(rng) << std::endl;
std::cout << rand() % LENGHT << std::endl;

return rand() % LENGHT;
}

问题在于第一个值始终相同 - 17LENGTH等于 30。

因此,生成随机数的最旧版本正在工作 - 因为它显示随机数,但新版本不起作用,因为它始终显示 17。

我尝试将种子定义移至代码的另一部分,但没有帮助。

最佳答案

您的代码存在几个问题。

  1. 您混合了两个标准随机数库,一个旧的随机数库带有 srandrand新的,带有 std::uniform_int_distributionstd::default_random_engine 。不要使用旧的库。虽然其实现很可能随着时间的推移而得到改进,但自从引入 C 语言以来,计算机科学已经取得了进步。

    所以,这是第一个修复:

#include <random>

int randomSpawn()
{
const int LENGHT = 30;
unsigned seed = time(NULL);
std::default_random_engine rng(seed);
std::uniform_int_distribution<int> d(1, LENGHT);

return d(rng);
}
  • 现在是第二个错误:每次调用 randomSpawn 时都会创建并初始化一个新的随机数生成器。这是完全错误的。通常,每个程序(或线程)仅使用一个随机数生成器,如果使用更多,请务必小心不要混合它们。并且您总是将其初始化一次。原因是随机数生成器应该很快,因此它们生成的确定性序列看起来是随机的,但实际上并非如此。这些序列中的数字是如此不相关,以至于大多数用户都可以接受它们只是伪随机的。因此,让我们将生成器移出函数:
  • #include <iostream>
    #include <random>

    int randomSpawn(std::default_random_engine & rng)
    {
    const int LENGHT = 30;
    std::uniform_int_distribution<int> d(1, LENGHT);
    return d(rng);
    }

    int main()
    {
    unsigned seed = time(NULL);
    std::default_random_engine rng(seed);

    for (int i = 0; i < 10; i++)
    std::cout << randomSpawn(rng) << "\n";
    }

    唉!这仍然会在序列中产生相同的数字!第一次运行:

    19
    23
    2
    8
    24
    13
    17
    22
    19
    28

    下次运行:

    19
    29
    11
    6
    17
    12
    13
    26
    25
    12
  • 代码似乎可以工作,但第一个“随机”数字在我的机器上始终是 19,在你的机器上始终是 17。实际上,我想重要的不是机器,而是初始化程序,即 time(NULL) ,实际上,在现代 C++ 中,应该拼写为 time(nullptr) 。每次调用此函数时,您都会收到自所谓的纪元以来已经过去的秒数。如果您手动测试程序,此函数会返回巨大的值,这些值之间相差一个小整数,对应于连续程序测试之间的一小部分秒数。

    人们使用过time(nullptr)几十年来,他们的程序运行得非常好。所以这段代码并不是错误。错误在于使用随机数生成器而不了解它们的内部构造方式。重要的是default_random_engine实现定义的。在我的系统中,它解析为 std::minstd_rand0 ,它早在 1969 年就已经开发出来,很可能只是出于兼容性原因才包含在标准 C++ 库中。它属于一类线性同余随机数生成器,它的“随机性”有时是值得怀疑的,这是你自己亲眼所见的。要查看此生成器生成的第一个数字的“非随机”程度,只需运行以下代码:

  • for (int i = 0; i < 5; i++)
    {
    std::default_random_engine de (i + 1'000'000);
    std::cout << de() << "\n";
    }

    在我的机器上我得到:

    1774614471
    1774631278
    1774648085
    1774664892
    1774681699

    这是彼此非常接近的数字。

  • 所以让我们使用更好的东西:
  • int randomSpawn(std::mt19937 & rng)
    {
    const int LENGHT = 30;
    std::uniform_int_distribution<int> d(1, LENGHT);
    return d(rng);
    }

    int main()
    {
    unsigned seed = time(nullptr);
    std::mt19937 rng(seed);

    for (int i = 0; i < 10; i++)
    std::cout << randomSpawn(rng) << "\n";
    }

    在这里,我明确使用了随机数生成器(不仅在 C++ 中)的黄金标准:来自 Mersenne Twister 随机数生成器系列的生成器。正如您可以测试的那样,现在对生成器的第一次调用已经生成了一个“随机”数字。

    如果您想确保第一个数字是“真正”随机的,您可以“预热”生成器:

        unsigned seed = time(nullptr);
    std::mt19937 rng(seed);
    for (int i = 0; i < 10; i++) // warm up 10 times to decorelate with seed
    rng();
    for (int i = 0; i < 10; i++)
    std::cout << randomSpawn(rng) << "\n";

    或者,您可以使用不同的种子初始化方法:

        std::random_device rd;
    unsigned seed = rd(); // produces a really "random" number
    std::mt19937 rng(seed);
    for (int i = 0; i < 10; i++)
    std::cout << randomSpawn(rng) << "\n";

    关于c++ - 第一个随机数始终相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75922552/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com