使用TR1 / dev / random在C ++中生成随机数(弹性到<1秒运行)

时间:2011-12-28 20:58:29

标签: c++ random random-seed

我希望在C ++中生成0到1之间的统一随机数,其方式不使用标准rand()srand(time(NULL))方法。原因是如果我在我的时钟的同一秒内多次运行应用程序,种子将完全相同并产生相同的输出。

我不想依赖boost或OS /编译器细节。可以假设x86。

似乎另一种方法是使用TR1(我没有C ++ 11)并以某种方式播种/dev/random

现在我有了这个,但它仍然使用time(NULL)作为种子,在1秒内不能正常运行:

#include <iostream> 
#include <tr1/random> 

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed(time(NULL)); 
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 

3 个答案:

答案 0 :(得分:7)

根据OP的要求发布:

这仍然是一些特定于编译器的,但仍可用于几乎所有x86定位编译器:

#ifdef _WIN32

//  Windows
#define rdtsc  __rdtsc

#else

//  For everything else
unsigned long long rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((unsigned long long)hi << 32) | lo;
}

#endif

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed( rdtsc() );    //  Seed with rdtsc.
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 

这里的想法是使用rdtsc循环计数器为随机数生成器播种。

这可行的原因是因为rdtsc循环计数器以与CPU频率大约(通常相同)的速度迭代。因此,两次调用返回相同值的可能性非常小 - 从而使其成为RNG的优秀种子。

答案 1 :(得分:4)

[tr.rand.device]中的TR1指定一个random_device类,它从依赖于实现的源生成无符号整数。所以以下内容应该有效,尽管我自己还没有编译它:

int main() {
  std::tr1::random_device dev_random;
  std::tr1::mt19937 eng(dev_random());
  ...

在TR1中,直接传递dev_random而不调用它工作并更随机地初始化eng的状态,但在C ++ 11中你必须将种子参数包装到另一个类中。由于调用参数在两个库中均有效,因此除非您有更苛刻的需求,否则我会这样做是为了可维护性。

答案 2 :(得分:1)

您的问题与种子随机数生成器的方式有关。显然,播种时间(NULL)将在播种时在该秒内产生相同的PRNG序列。这是种子兰的最常见方式,但不幸的是,由于这个问题,这是不好的做法。不仅如此,我还读到它会导致结果出现偏差。

请注意,如果使用相同的值播种,每个PRNG都会生成相同的结果。所以你的问题与发电机无关,更多的是与播种有关。

几个星期前我在这里问了一个关于播种的问题,并给出了以下文章的链接,你也可能会发现它很有用。 Good Practice in (Pseudo) Random Number Generation for Bioinformatics Applications 请参阅有关播种或预热发电机的部分。

rand()不是最好的随机数生成器,但在许多情况下适用,只要它被正确播种。如果你想要一个更好的东西,重复序列非常大,那么在那个链接中提供了一些。或者使用基于TR1的。就个人而言,我会使用更便携的基于C ++ 03的代码,并避开TR1。

另请考虑Multiply with carry作为替代PRNG算法。