【问题标题】:Why does rand() yield the same sequence of numbers on every run?为什么 rand() 每次运行都会产生相同的数字序列?
【发布时间】:2012-03-16 13:44:46
【问题描述】:

每次我使用rand() 运行程序时,都会得到相同的结果。

例子:

#include <iostream>
#include <cstdlib>

using namespace std;

int random (int low, int high) {
    if (low > high)
        return high;
    return low + (rand() % (high - low + 1));
}

int main (int argc, char* argv []) {
    for (int i = 0; i < 5; i++)
        cout << random (2, 5) << endl;
}

输出:

3
5
4
2
3

每次我运行程序时,它每次都会输出相同的数字。有没有办法解决这个问题?

【问题讨论】:

    标签: c++ random


    【解决方案1】:

    未设置随机数生成器的种子。

    如果你打电话给srand((unsigned int)time(NULL)) 那么你会得到更多的随机结果:

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    int main() {
        srand((unsigned int)time(NULL));
        cout << rand() << endl;
        return 0;
    }
    

    原因是rand() 函数生成的随机数实际上并不是随机的。这简直是​​一种转变。维基百科对伪随机数生成器的含义给出了更好的解释:确定性随机位生成器。每次您调用 rand() 时,它都会生成种子和/或最后一个随机数(C 标准没有指定使用的算法,尽管 C++11 有指定一些流行算法的工具),运行一个对这些数字进行数学运算,并返回结果。因此,如果种子状态每次都相同(如果您不使用真正的随机数调用 srand),那么您将始终得到相同的“随机”数字。

    如果你想了解更多,可以阅读以下内容:

    http://www.dreamincode.net/forums/topic/24225-random-number-generation-102/

    http://www.dreamincode.net/forums/topic/29294-making-pseudo-random-number-generators-more-random/

    【讨论】:

    • 如果我在 .h 文件中有该功能怎么办?如果不在 main 中,在哪里设置种子的合适位置?
    • 你可以在一个你知道会在rand()被第一次调用之前构建的对象的构造函数中设置它(例如,如果需要,在一个静态/单例对象中)
    【解决方案2】:

    如果您在没有先调用srand() 的情况下调用rand(),它的行为就像您已经隐式调用了srand(1)。标准C99 7.20.2.2 The srand functioncstdlib 所基于)的相关位指出:

    如果在调用 srand 之前调用了 rand,则应生成与第一次调用 srand 时相同的序列,种子值为 1。

    换句话说,您每次都得到相同的序列。您可以将main 更改为:

    int main (int argc, char* argv []) {
        srand (time (0));  // needs ctime header.
        for (int i = 0; i < 5; i++)
            cout << random (2, 5) << endl;
        wait ();
    }
    

    修复此问题,假设您每秒运行的次数不超过一次。

    如前所述,您需要 ctime 标头。您还应该加入cstdlib,因为那是randsrand 的所在地。使用cXXX 标头而不是XXX.h 标头通常也是一个好主意(例如,cmath 而不是math.h)。

    所以,在进行了所有这些更改(并使用明确的命名空间,我更喜欢虽然其他人可能不喜欢),我最终会得到:

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    
    void wait () {
        int e;
        std::cin >> e;
    }
    
    int random (int low, int high) {
        if (low > high) return high;
        return low + (std::rand() % (high - low + 1));
    }
    
    int main (int argc, char* argv []) {
        std::srand (std::time (0));
        for (int i = 0; i < 5; i++)
            std::cout << random (2, 5) << '\n';
        wait ();
    }
    

    每次我运行它时都会给出不同的序列,反正有几次。显然,数据何时重复存在硬性限制(只有 45 种可能性),输出的“随机”性质意味着它也可能在此之前重复 :-)

    【讨论】:

      【解决方案3】:

      这是rand() 函数的一个特性。

      您拥有的不是随机数生成器,而是更严格地说是 "pseudorandom number generator"。能够为相同的种子(您使用 srand(x) 函数播种)重现相同的随机序列对于重现错误或在程序运行期间保持状态非常重要。

      就个人而言,我使用此功能能够在基于Monte Carlo 的地形渲染器中暂停/保持渲染进程。一个很好的副作用是您能够保证在不同机器上进行不同的蒙特卡洛实验,因此能够生成有保证的不同结果,然后可以在最后一步中减少到更高质量的最终结果(当然您可以稍后重用这种更高质量的最终结果会产生更高质量的结果)。

      但是请注意,C 和 C++ 都没有定义来自rand() 的数字序列。因此,如果您需要跨平台的有保证的序列,请使用 C++11 的新随机数生成器之一(例如 Mersenne Twister),自己动手制作(但是,有些生成器几乎很难掌握,因为它们中的大多数都依赖于特定的溢出行为他们的实现可能不是微不足道的),或使用第三方组件(例如 boost::random)。

      【讨论】:

        【解决方案4】:

        您需要为随机数生成器播种(参见函数“srand”)。假设你不做密码学,那么用 'time' 的输出播种它可能就足够了。

        【讨论】:

          【解决方案5】:

          您实际上得到的是伪随机数。为了让它们“更随机”,您可以使用“改变”的东西(最常见的是当前时间)为随机数生成器播种。

          【讨论】:

          • Nit:从数学上讲,这不会让它们“更随机”。
          • 是的,但在 OP 的问题的上下文中......(加上引号;-)
          【解决方案6】:

          C++ 使用伪随机数生成器。从本质上讲,这意味着您的程序正在读取一个非常长的预定数字列表。当您重复运行程序时,它每次都会给出相同的数字,因为它每次都从该数字列表的开头读取。

          您可以将程序设置为从列表中的第 n 个数字开始。您可以使用时间或温度或其他任何“随机”的东西。 (对于温度,您可以取温度的最后一位,或使用它后面的小数位。)

          【讨论】:

            【解决方案7】:

            使用随机化()。它会自动播种该值。 或者如果你想使用 rand() 那么你可以使用 srand(seedvalue);种子值可以是系统时间之类的任何东西......每次都会给你不同的随机数。

            【讨论】:

            • randomize 不是标准的 C++ 函数。你说的是哪个平台?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-03-29
            • 1970-01-01
            • 2015-08-29
            • 1970-01-01
            • 2021-12-20
            • 2023-01-22
            相关资源
            最近更新 更多