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

generating random numbers in C++ using TR1 /dev/random (resilient to <1 second runs)

本文关键字:运行 lt random dev TR1 生成 C++ 随机数 使用      更新时间:2023-10-16

我想在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; 
} 

应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的优秀种子。

TR1 in [tr.rand.device]指定了一个random_device类,它从一个依赖于实现的源生成无符号整数。所以下面的代码应该可以工作,尽管我没有自己编译:

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

在TR1中,直接传递dev_random而不调用它可以更随机地初始化eng的状态,但在c++ 11中,您必须将seed参数包装到另一个类中。由于调用参数在两个库中都可以工作,所以我将这样做是为了可维护性,除非您有更苛刻的需求。

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

注意如果使用相同的值,每个PRNG将产生相同的结果。所以你的问题与生成器无关,更多的是播种。

就在几周前,我在这里问了一个关于播种的问题,并给出了以下文章的链接,您可能也会发现这篇文章很有用。生物信息学应用中(伪)随机数生成的良好实践请参阅播种或预热生成器一节。

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

也考虑乘进作为一种替代的PRNG算法。