【问题标题】:Random number generator - why seed every time随机数生成器 - 为什么每次都播种
【发布时间】:2014-01-05 08:59:49
【问题描述】:

我对 c 和 c++ 比较陌生。在我常用的编程语言 java 中,很容易实现随机数生成。只需从名为 Math 的类中调用静态随机方法即可。

int face = ((int)(Math.random() * 6) + 1);

模拟掷骰子...

在 c 和 c++ 中,您必须通过调用 srand 函数来“为随机数生成器提供种子”

srand ( time(NULL) );

这样做有什么意义 - 我的意思是每次运行代码时都必须为随机数生成器播种有什么好处吗?

【问题讨论】:

  • 注意:您不应该在每次运行特定代码时都为其播种;你应该在每次进程开始时播种它。
  • @RogerLipscombe 这真的取决于你想要达到的目标。
  • wikipedia 的文章很不错。在 Java 中,它仍然在第一次调用时播种 PRNG,但它是 under the hood.

标签: c++ c


【解决方案1】:

给定相同的种子,伪随机数生成器每次都会产生相同的序列。因此,这取决于每次运行时是否需要不同的伪随机数序列。

这真的取决于您的需求。有时您想重复一个序列。而你不这样做的时候。您需要了解每个特定应用程序的需求。

您绝不能做的一件事是在生成单个序列期间重复播种。这样做很可能会破坏序列的分布。

【讨论】:

  • 种子是什么意思?我搜索了谷歌,大多数链接都没有给出任何解释。
  • “你绝不能做的一件事是在生成单个序列的过程中重复播种。这样做很可能会破坏序列的分布。”你能解释一下为什么吗?在我看来,每次播种只会让它“更随机”。
【解决方案2】:

通常所说的随机数生成器实际上是一个伪随机数生成器。这通常意味着如果您提供该序列的“密钥”(称为“种子”),您可以生成相同的随机序列。当您希望测试基于随机化的算法并且需要确保可重复的结果时,这非常有用。

如果您不“播种”随机数生成器,默认情况下会使用 一些(通常基于系统时间)随机数播种,因此每次运行时都会生成不同的序列你的程序。

【讨论】:

    【解决方案3】:

    如果不给生成器做种子,每次运行程序都会有相同的种子,而且每次的随机数序列都是一样的。

    另请注意,您应该只在程序开始时为生成器播种一次。

    【讨论】:

    • 我以为正好相反,如果我们给生成器播种,那么每次都会得到相同的随机序列?
    • @user5965026 这个想法是使用 unique 种子。这就是为什么使用time 的结果如此普遍的原因,它通常返回一个具有秒分辨率的值。
    【解决方案4】:

    优点是你可以通过提供相同的种子来重复一个随机数序列。

    Elite 游戏使用它来将由数千颗星星组成的整个世界存储为一个数字。 为了第二次生成完全相同的世界,刚才提供了相同的种子。

    【讨论】:

    • 这对于调试涉及随机数生成的代码非常有用。
    • 确实如此。如果您想要大多数不可预测的种子但能够重现您观察到的行为,请让您的程序显示/记录使用的种子以及结果。并添加一个命令行开关来指定种子,使用它而不是time(NULL)(如果存在)。
    • 这对模拟也很方便。
    【解决方案5】:

    伪随机数生成器需要种子来生成与以前的随机数序列不同的随机数序列(并非总是如此)。如果您不想要重复序列,则需要为伪随机数生成器播种。

    试试这些代码,看看有什么不同。
    没有种子:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
            printf("%d", rand()%6 + 1);
    }  
    

    有种子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main()
    {
            srand(time(NULL));
            printf("%d", rand()%6 + 1);
    }
    

    【讨论】:

      【解决方案6】:

      随机数生成器并不是真正随机的:假设你用 12 播种并生成 100 个随机数,重复该过程并再次用 12 播种并生成另外 100 个随机数,它们将是相同的。

      在创建它们的代码之后,我附上了 2 个运行的小样本,每个运行有 20 个条目,每个条目都有 12 个种子来说明:

      #include <iostream>
      #include <cstdlib>
      
      using namespace std;
      
      int main()
      {
          srand(12);
         for (int i =0;i<100; i++)
         {
             cout << rand() << endl;
         }
         return 0;
      }
      

      为了避免这种重复,通常使用更独特的值,因为时间总是在变化,两个程序同时生成随机序列的机会很小(尤其是在毫秒级别时) ,人们可以合理地安全地将时间用作几乎独一无二的种子。

      要求:每个您需要生成的唯一随机序列只需要进行一次播种。

      但是,这有一个意想不到的好处/坏处: 如果知道生成第一个序列的确切时间,那么将来可以通过手动输入种子值来重新生成确切的序列,从而导致随机数生成器以与以前相同的方式逐步完成其过程(这是存储随机序列的好处,而保留其随机性的坏处)。

      【讨论】:

        【解决方案7】:

        在 C/C++ 中,掷骰子的模拟如下:

        int face = (rand() % 6) + 1);
                           ^
                           |___________ Modulo operator
        

        % 6 将随机数限制为 0 到 5,而 + 1 用于抵消限制,因此变为 1 到 6。 p>

        【讨论】:

        • OP在java中提到Math.random(),它返回一个0.0到1.0之间的浮点数。
        • @KlasLindbäck 感谢您的澄清。我编辑了我的答案。据我所知,C/C++ 中也没有 Math.random()
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-14
        • 1970-01-01
        • 2010-11-01
        • 2019-07-16
        • 2016-07-22
        • 1970-01-01
        相关资源
        最近更新 更多