C++ 推荐的初始化srand的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/322938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Recommended way to initialize srand?
提问by Gary Richardson
I need a 'good' way to initialize the pseudo-random number generator in C++. I've found an articlethat states:
我需要一种“好”的方法来初始化 C++ 中的伪随机数生成器。我发现一篇文章指出:
In order to generate random-like numbers, srand is usually initialized to some distinctive value, like those related with the execution time. For example, the value returned by the function time (declared in header ctime) is different each second, which is distinctive enough for most randoming needs.
为了生成类似随机的数字,srand 通常被初始化为一些独特的值,比如那些与执行时间相关的值。例如,函数 time 返回的值(在头文件 ctime 中声明)每秒都不同,这足以满足大多数随机化需求。
Unixtime isn't distinctive enough for my application. What's a better way to initialize this? Bonus points if it's portable, but the code will primarily be running on Linux hosts.
Unixtime 对我的应用程序来说不够独特。什么是更好的初始化方法?如果它是可移植的,则可以加分,但代码将主要在 Linux 主机上运行。
I was thinking of doing some pid/unixtime math to get an int, or possibly reading data from /dev/urandom
.
我正在考虑做一些 pid/unixtime 数学来获得一个 int,或者可能从/dev/urandom
.
Thanks!
谢谢!
EDIT
编辑
Yes, I am actually starting my application multiple times a second and I've run into collisions.
是的,我实际上每秒多次启动我的应用程序,并且遇到了冲突。
采纳答案by Martin York
The best answer is to use the Boost random number stuff. Or if you have access to C++11 use the <random>
header.
最好的答案是使用 Boost 随机数的东西。或者,如果您有权访问 C++11,请使用<random>
标头。
But if we are talking about rand()
and srand()
The best way is just to use time()
:
但是,如果我们正在谈论rand()
并且srand()
最好的方法就是使用time()
:
int main()
{
srand(time(NULL));
...
}
Be sure to do this at the beginning of your program, and not every time you call rand()
!
确保在程序开始时执行此操作,而不是每次调用rand()
!
Every time you start up, time() will return a unique value (unless you start the application multiple times a second). In 32 bit systems, it will only repeat every 60 years or so.
每次启动时,time() 都会返回一个唯一值(除非您每秒多次启动应用程序)。在 32 位系统中,它只会每 60 年左右重复一次。
I know you don't think time is unique enough but I find that hard to believe. But I have been known to be wrong.
我知道你认为时间不够独特,但我觉得这很难相信。但我已经知道是错的。
If you are starting a lot of copies of your application simultaneously you could use a timer with a finer resolution. But then you run the risk of a shorter time period before the value repeats.
如果您同时启动大量应用程序副本,则可以使用分辨率更高的计时器。但是,在该值重复之前,您将面临更短时间段的风险。
OK, so if you really think you are starting multiple applications a second.
Then use a finer grain on the timer.
好的,所以如果你真的认为你正在启动多个应用程序。
然后在计时器上使用更细的颗粒。
int main()
{
struct timeval time;
gettimeofday(&time,NULL);
// microsecond has 1 000 000
// Assuming you did not need quite that accuracy
// Also do not assume the system clock has that accuracy.
srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
// The trouble here is that the seed will repeat every
// 24 days or so.
// If you use 100 (rather than 1000) the seed repeats every 248 days.
// Do not make the MISTAKE of using just the tv_usec
// This will mean your seed repeats every second.
}
回答by Jonathan Wright
This is what I've used for small command line programs that can be run frequently (multiple times a second):
这是我用于可以频繁运行的小型命令行程序(每秒多次)的方法:
unsigned long seed = mix(clock(), time(NULL), getpid());
Where mix is:
混合在哪里:
// http://www.concentric.net/~Ttwang/tech/inthash.htm
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
a=a-b; a=a-c; a=a^(c >> 13);
b=b-c; b=b-a; b=b^(a << 8);
c=c-a; c=c-b; c=c^(b >> 13);
a=a-b; a=a-c; a=a^(c >> 12);
b=b-c; b=b-a; b=b^(a << 16);
c=c-a; c=c-b; c=c^(b >> 5);
a=a-b; a=a-c; a=a^(c >> 3);
b=b-c; b=b-a; b=b^(a << 10);
c=c-a; c=c-b; c=c^(b >> 15);
return c;
}
回答by Evan Teran
if you need a better random number generator, don't use the libc rand. Instead just use something like /dev/random
or /dev/urandom
directly (read in an int
directly from it or something like that).
如果您需要更好的随机数生成器,请不要使用 libc rand。相反,只需使用类似/dev/random
或/dev/urandom
直接的东西(int
直接从它或类似的东西中读取)。
The only real benefit of the libc rand is that given a seed, it is predictable which helps with debugging.
libc rand 唯一真正的好处是,给定一个种子,它是可预测的,这有助于调试。
回答by shoosh
On windows:
在窗户上:
srand(GetTickCount());
provides a better seed than time()
since its in milliseconds.
提供比time()
以毫秒为单位更好的种子。
回答by bames53
C++11 random_device
C++11 random_device
If you need reasonable quality then you should not be using rand() in the first place; you should use the <random>
library. It provides lots of great functionality like a variety of engines for different quality/size/performance trade-offs, re-entrancy, and pre-defined distributions so you don't end up getting them wrong. It may even provide easy access to non-deterministic random data, (e.g., /dev/random), depending on your implementation.
如果您需要合理的质量,那么您首先不应该使用 rand();你应该使用<random>
图书馆。它提供了许多很棒的功能,例如用于不同质量/大小/性能权衡的各种引擎、可重入性和预定义的分布,因此您最终不会弄错它们。它甚至可以提供对非确定性随机数据(例如,/dev/random)的轻松访问,具体取决于您的实现。
#include <random>
#include <iostream>
int main() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist{1,100};
for (int i=0; i<50; ++i)
std::cout << dist(eng) << '\n';
}
eng
is a source of randomness, here a built-in implementation of mersenne twister. We seed it using random_device, which in any decent implementation will be a non-determanistic RNG, and seed_seq to combine more than 32-bits of random data. For example in libc++ random_device accesses /dev/urandom by default (though you can give it another file to access instead).
eng
是随机性的来源,这里是梅森扭曲器的内置实现。我们使用 random_device(在任何体面的实现中都是非确定性 RNG)和 seed_seq 来组合超过 32 位的随机数据。例如,在 libc++ 中, random_device 默认访问 /dev/urandom (尽管您可以给它另一个文件来访问)。
Next we create a distribution such that, given a source of randomness, repeated calls to the distribution will produce a uniform distribution of ints from 1 to 100. Then we proceed to using the distribution repeatedly and printing the results.
接下来,我们创建一个分布,在给定随机源的情况下,重复调用该分布将产生从 1 到 100 的整数分布。然后我们继续重复使用该分布并打印结果。
回答by user39307
Best way is to use another pseudorandom number generator. Mersenne twister (and Wichmann-Hill) is my recommendation.
最好的方法是使用另一个伪随机数生成器。Mersenne twiner(和 Wichmann-Hill)是我的推荐。
回答by FL4SOF
i suggest you see unix_random.c file in mozilla code. ( guess it is mozilla/security/freebl/ ...) it should be in freebl library.
我建议您在 mozilla 代码中查看 unix_random.c 文件。(猜测它是 mozilla/security/freebl/ ...)它应该在 freebl 库中。
there it uses system call info ( like pwd, netstat ....) to generate noise for the random number;it is written to support most of the platforms (which can gain me bonus point :D ).
在那里它使用系统调用信息(如 pwd、netstat ....)为随机数生成噪声;它被编写为支持大多数平台(这可以获得我的加分点:D)。
回答by Edouard A.
The real question you must ask yourself is what randomness quality you need.
您必须问自己的真正问题是您需要什么样的随机性质量。
libc random is a LCG
libc random 是LCG
The quality of randomness will be low whatever input you provide srand with.
无论您向 srand 提供什么输入,随机性的质量都会很低。
If you simply need to make sure that different instances will have different initializations, you can mix process id (getpid), thread id and a timer. Mix the results with xor. Entropy should be sufficient for most applications.
如果您只是需要确保不同的实例具有不同的初始化,您可以混合使用进程 ID (getpid)、线程 ID 和计时器。将结果与异或混合。对于大多数应用程序,熵应该足够了。
Example :
例子 :
struct timeb tp;
ftime(&tp);
srand(static_cast<unsigned int>(getpid()) ^
static_cast<unsigned int>(pthread_self()) ^
static_cast<unsigned int >(tp.millitm));
For better random quality, use /dev/urandom. You can make the above code portable in using boost::thread and boost::date_time.
要获得更好的随机质量,请使用 /dev/urandom。您可以使用 boost::thread 和 boost::date_time 使上述代码可移植。
回答by swalog
The c++11
version of the top voted post by Jonathan Wright:
c++11
乔纳森·赖特 (Jonathan Wright) 最高投票帖子的版本:
#include <ctime>
#include <random>
#include <thread>
...
const auto time_seed = static_cast<size_t>(std::time(0));
const auto clock_seed = static_cast<size_t>(std::clock());
const size_t pid_seed =
std::hash<std::thread::id>()(std::this_thread::get_id());
std::seed_seq seed_value { time_seed, clock_seed, pid_seed };
...
// E.g seeding an engine with the above seed.
std::mt19937 gen;
gen.seed(seed_value);
回答by Dolda2000
As long as your program is only running on Linux (and your program is an ELF executable), you are guaranteed that the kernel provides your process with a unique random seed in the ELF aux vector. The kernel gives you 16 random bytes, different for each process, which you can get with getauxval(AT_RANDOM)
. To use these for srand
, use just an int
of them, as such:
只要您的程序仅在 Linux 上运行(并且您的程序是 ELF 可执行文件),您就可以保证内核在 ELF 辅助向量中为您的进程提供唯一的随机种子。内核为您提供 16 个随机字节,每个进程都不同,您可以使用getauxval(AT_RANDOM)
. 要将这些用于srand
,请仅使用其中的一个int
,例如:
#include <sys/auxv.h>
void initrand(void)
{
unsigned int *seed;
seed = (unsigned int *)getauxval(AT_RANDOM);
srand(*seed);
}
It may be possible that this also translates to other ELF-based systems. I'm not sure what aux values are implemented on systems other than Linux.
这也可能转化为其他基于 ELF 的系统。我不确定在 Linux 以外的系统上实现了哪些 aux 值。