C++ 需要一种很好的技术来播种不使用 time() 的 rand()
C++ need a good technique for seeding rand() that does not use time()
我有一个 bash 脚本可以启动许多客户端进程。这些是我用来测试多人游戏的 AI 游戏玩家,大约有 400 个连接。
我遇到的问题是AI播放器使用
srand( time(nullptr) );
但是如果所有玩家都大约在同一时间开始,他们将经常收到相同的 time() 值,这意味着他们都在同一个 rand() 序列上。
部分测试过程是为了确保如果大量客户端几乎同时尝试连接,服务器可以处理。
我考虑过使用类似
的东西
srand( (int) this );
或类似的,基于每个实例都有唯一内存地址的想法。
还有其他更好的方法吗?
如果 仅需要可重现的结果,则使用随机数种子。这对于地图生成之类的事情非常方便,您希望地图是随机的,但您希望它是基于种子的可预测随机性。
在大多数情况下,您不希望这样,您实际上需要随机数,最好的方法是通过标准库生成器函数:
#include <random>
std::random_device rd;
std::map<int, int> hist;
std::uniform_int_distribution<int> dist(0, 5);
int random_die_roll = dist(rd);
在这种情况下不需要也不推荐种子。 "random device" 开始正确播种 PRNG(伪随机数生成器)以确保不可预测的结果。
同样,不要使用srand(time(NULL))
,因为它是一种非常古老、非常糟糕的初始化随机数的方法,而且它是高度可预测的。在现代计算机上旋转一百万个可能的种子以找到匹配的输出是微不足道的。
将随机种子用于伪随机生成器。
std::random_device
是昂贵的随机数据。 (贵如慢)
你用它来播种 prng 算法。 mt19937 是您需要的最后一个 prng 算法。
如果您的需要,您可以选择通过分发提供它来跟进它。即,如果您需要某个范围内的值而不是生成器提供的值。
std::random_device rd;
std::mt19937 generator(rd());
现在 rand()
和 srand()
已经过时了。
普遍接受的方法是从 std::random_device
播种一个 伪随机数生成器 。在提供非确定性随机源的平台上,std::random_device
需要使用它们来提供高质量的随机数。
然而,在收集足够的熵时,它可能会变慢甚至阻塞。因此一般只用于提供种子。
标准库提供的 mersenne twister 是一个高质量但高效的随机引擎:
inline
std::mt19937& random_generator()
{
thread_local static std::mt19937 mt{std::random_device{}()};
return mt;
}
template<typename Number>
Number random_number(Number from, Number to)
{
static_assert(std::is_integral<Number>::value||std::is_floating_point<Number>::value,
"Parameters must be integer or floating point numbers");
using Distribution = typename std::conditional
<
std::is_integral<Number>::value,
std::uniform_int_distribution<Number>,
std::uniform_real_distribution<Number>
>::type;
thread_local static Distribution dist;
return dist(random_generator(), typename Distribution::param_type{from, to});
}
我正在尝试使用 errno 为随机函数播种:
#include <stddef.h>
#include <string.h>
int main(void){
srand(&errno);
srand(strerror(0));
return rand();
}
我有一个 bash 脚本可以启动许多客户端进程。这些是我用来测试多人游戏的 AI 游戏玩家,大约有 400 个连接。
我遇到的问题是AI播放器使用
srand( time(nullptr) );
但是如果所有玩家都大约在同一时间开始,他们将经常收到相同的 time() 值,这意味着他们都在同一个 rand() 序列上。
部分测试过程是为了确保如果大量客户端几乎同时尝试连接,服务器可以处理。
我考虑过使用类似
的东西srand( (int) this );
或类似的,基于每个实例都有唯一内存地址的想法。
还有其他更好的方法吗?
如果 仅需要可重现的结果,则使用随机数种子。这对于地图生成之类的事情非常方便,您希望地图是随机的,但您希望它是基于种子的可预测随机性。
在大多数情况下,您不希望这样,您实际上需要随机数,最好的方法是通过标准库生成器函数:
#include <random>
std::random_device rd;
std::map<int, int> hist;
std::uniform_int_distribution<int> dist(0, 5);
int random_die_roll = dist(rd);
在这种情况下不需要也不推荐种子。 "random device" 开始正确播种 PRNG(伪随机数生成器)以确保不可预测的结果。
同样,不要使用srand(time(NULL))
,因为它是一种非常古老、非常糟糕的初始化随机数的方法,而且它是高度可预测的。在现代计算机上旋转一百万个可能的种子以找到匹配的输出是微不足道的。
将随机种子用于伪随机生成器。
std::random_device
是昂贵的随机数据。 (贵如慢)
你用它来播种 prng 算法。 mt19937 是您需要的最后一个 prng 算法。
如果您的需要,您可以选择通过分发提供它来跟进它。即,如果您需要某个范围内的值而不是生成器提供的值。
std::random_device rd;
std::mt19937 generator(rd());
现在 rand()
和 srand()
已经过时了。
普遍接受的方法是从 std::random_device
播种一个 伪随机数生成器 。在提供非确定性随机源的平台上,std::random_device
需要使用它们来提供高质量的随机数。
然而,在收集足够的熵时,它可能会变慢甚至阻塞。因此一般只用于提供种子。
标准库提供的 mersenne twister 是一个高质量但高效的随机引擎:
inline
std::mt19937& random_generator()
{
thread_local static std::mt19937 mt{std::random_device{}()};
return mt;
}
template<typename Number>
Number random_number(Number from, Number to)
{
static_assert(std::is_integral<Number>::value||std::is_floating_point<Number>::value,
"Parameters must be integer or floating point numbers");
using Distribution = typename std::conditional
<
std::is_integral<Number>::value,
std::uniform_int_distribution<Number>,
std::uniform_real_distribution<Number>
>::type;
thread_local static Distribution dist;
return dist(random_generator(), typename Distribution::param_type{from, to});
}
我正在尝试使用 errno 为随机函数播种:
#include <stddef.h>
#include <string.h>
int main(void){
srand(&errno);
srand(strerror(0));
return rand();
}