2011-12-28 83 views
6

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

我不想依赖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; 
} 
+0

你是否愿意使用OS /编译器特有的功能? – Mysticial 2011-12-28 21:00:24

+0

我想避免这个......我将在各种系统上部署这个 – gnychis 2011-12-28 21:01:10

+0

各种各样?他们仍然是x86吗? – Mysticial 2011-12-28 21:01:45

回答

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周期计数器。

之所以这个作品是因为在有关(往往是相同的)速度与CPU频率rdtsc周期计数器进行迭代。因此,两次调用返回相同值的机会非常渺茫 - 从而使它成为RNG的优秀种子。

1

你的问题是有关您种子随机数生成的方式。很明显,随着播种时间的增加(NULL)将在接下来的秒内产生相同的PRNG序列。这是种植兰特最常见的方式,但不幸的是,由于这个问题,这是不好的做法。不仅如此,我读到它可能会导致结果的偏见。

请注意,如果用相同的值接种,每个PRNG将产生相同的结果。所以你的问题与发电机无关,更重要的是播种。

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

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

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

4

TR1在[tr.rand.device]指定一个random_device类,从依赖于实现的源产生的无符号整数。所以下面应该工作,虽然我没有编译它自己:

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

在TR1,直接传递dev_random不调用它的工作原理,更随机初始化工程的状态,但在C++ 11你必须包装的种子参数转换为另一个类。既然调用这个参数在两个库中都有效,除非你有更多的需求,否则我会这样做以保持可维护性。

+0

请注意,您无法保证从random_device()构造函数获得_which_ random设备。它可能是'/ dev/random','/ dev/urandom','rdtsc',http://en.wikipedia.org/wiki/RdRand,甚至是另一个伪rng。实现可以为构造函数定义一个字符串参数,以在选项之间进行选择,但默认设置应该不错。 – 2011-12-28 21:37:06

+1

random_device是一个函数对象,所以'eng(dev_random())' – Cubbi 2011-12-28 22:10:51

+0

@Cubbi:Nope:引擎有一个构造函数接受一个整数,一个构造函数接受一个函数对象:“'X(g)' - 创建一个引擎具有初始内部状态,由连续调用'g'的结果给出。“ - [tr.rand.req]表16.这允许它们填充它们的整个状态,而不仅仅是它的第一个单词。 (当然,有可能任何给定的实现都没有实现整个规范。) – 2011-12-28 22:29:22