C++中的序列随机数

Sequential Random Numbers in C++?

本文关键字:随机数 C++      更新时间:2023-10-16

我正在寻找一种在C++中快速生成两个随机数的方法。该代码用于模具,滚动时需要生成一个随机数。我的代码目前看起来是这样的:

Die::Die() {
    srand(time(NULL));
}
void Die::roll() {
    value = rand() % 6 + 1;
}

如果我用这段代码创建两个对象,srand()作为一个静态(非基于实例)函数,将为所有对象生成一个新的种子。我也试过这样做:

void Die::roll() {
    srand(time(NULL));
    value = rand() % 6 + 1;
}

而不是在构造函数中使用它,但如果我像下面这样快速调用它们:

die0->roll();
die1->roll();

它们的价值通常是相等的。有没有什么方法可以让它每次都是随机的?谢谢你的帮助。:)

假设程序运行得足够快,时间(以秒为单位)通常会相同,这意味着你的种子会相同,也就是说你的随机值与相同。正如评论者所说,在其他地方进行随机种子(比如你的程序或线程的开始)。

问题是,如果srand在时间上发生得足够近,那么你正在用相同的值为rng播种,因此在每个种子之后获得的第一个值将是相同的。为了避免这种情况,可以确保播种只发生一次。例如,您可以从您的Die类中删除srand,并在首次使用Die之前播种。

或者,如果你不想让Die的使用者有调用srand的负担,你可以将srand保留在Die的构造函数中,但要注意不要用静态bool多次调用它。

Die::Die()
{
  static bool seeded = false;
  if (!seeded)
  {
    srand(time(NULL));
    seeded = true;
  }
}

请注意,这个srand仍然可以影响srand()和rand()的其他类,但这可能无关紧要。但是,如果您在定义的多个类中需要一个随机数,您可以考虑创建一个RNG单例来为您生成数字。

最不容易出错的方法是使用random标头中的uniform_int_distribution。这也避免了modulo bias,这是一个基本的例子:

#include <iostream>
#include <random>
 class Die
 {
   public:
     template <class Generator>
     void roll( Generator &g )
     {
         std::uniform_int_distribution<int> dist(1,6);
         std::cout << dist(g) ;
     }
   private:
 } ;
int main()
{
    std::random_device rd;
    std::mt19937 e1(rd());
    Die d1, d2 ;
    for (int n = 0; n < 10; ++n) {
            d1.roll( e1 ) ;
            std::cout << " , " ;
            d2.roll( e1 ) ;
            std::cout << std::endl ;
    }
}

或者,您也可以使用static成员,正如James所建议的:

class Die
{
   public:
     Die()  {} ;
     void roll()
     {
         std::uniform_int_distribution<int> dist(1,6);
         std::cout << dist(e1) ;
     }
   private:
      static std::random_device rd;    
      static std::mt19937 e1 ;
} ;

正如其他人所说,您不想再为生成器重新设定种子不止一次。如果Dierand的唯一用户(或者不是),您可以在名称空间范围内使用一个变量对其进行种子设定:

int seeded = (srand( time( NULL ) ), rand());

这是否是一个好主意取决于;它成功了无法复制代码运行以进行调试例如,目的。如果这是一个问题,您将希望1)记录您使用的种子,2)在命令行中添加一个选项指定种子;后者意味着从调用CCD_ 7main

(还请注意,我在中添加了对rand()的调用初始化。在至少一个广泛的实现中对rand()的第一个调用返回种子,这意味着它可以非常可预测。)