1

我正在寻找一种在 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();

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

4

4 回答 4

4

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

于 2013-08-19T12:08:50.323 回答
1

问题是,如果 srands 在时间上彼此足够接近,那么您将使用相同的值播种 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 单例来为您生成数字。

于 2013-08-19T12:28:35.807 回答
1

The least error prone method will be to use uniform_int_distribution from the random header. This also avoids modulo bias, this is basic example:

#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 ;
    }
}

Alternatively, you can also use static members, as James suggests:

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 ;
} ;
于 2013-08-19T12:29:37.493 回答
0

正如其他人所说,您不想多次重新播种生成器。如果Dierand(或者即使不是)的唯一用户,您可以使用名称空间范围内的变量来播种它:

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

这是否是一个好主意取决于;例如,它使得无法复制代码运行以进行调试。如果这是一个问题,您需要 1) 记录您使用的种子,以及 2) 在命令行中添加一个选项来指定种子;后者意味着调用srandfrom main

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

于 2013-08-19T13:12:16.917 回答