我希望在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;
}
答案 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算法。