在我之前的question中,我质疑srand(time(NULL))
的可移植性。这份题为Using rand()的文件提供了一种“将时间结果()作为rand()的种子便携地使用的方法;”。但是,我不明白“只是散列time_t的字节”意味着什么,也不知道代码的作用。
unsigned time_seed()
{
time_t now = time ( 0 );
unsigned char *p = (unsigned char *)&now;
unsigned seed = 0;
size_t i;
for ( i = 0; i < sizeof now; i++ )
seed = seed * ( UCHAR_MAX + 2U ) + p[i];
return seed;
}
srand ( time_seed() );
有人可以提供解释吗?
答案 0 :(得分:1)
散列time
的结果是为了避免可预测的种子值。它可以用在你可能没有像rand
这样不安全的伪随机数生成器的情况下,但仍然不希望客户端能够可预测地确定你的伪随机序列。
您可以通过time_t
来完成许多方法。一个非常简单的天真方法是简单地运行进程pid。这是Unix系统长期使用的经典方法;尽管如此,它并没有真正以安全的形式增加更多。您还可以从系统中包含其他形式的真实熵。其他替代方案将涉及适当的散列函数或其他数据点和散列的某种组合。散列函数的示例包括Bernstein的散列,Fowler–Noll–Vo hash或其他加密安全散列,如MD5或SHA1。但是,如果您要使用加密安全散列函数,您可能也应该使用加密安全随机数生成器。
由于它是用C ++标记的,因此只要您使用支持TR1或更高版本的C ++编译器,就可以使用标准库中提供的内置std::hash
函数。在GCC中,std::hash
函数是使用上面提到的FNV哈希实现的。
答案 1 :(得分:0)
Hashing time_t意味着通过对携带当前系统时间的结构中的值应用数学计算(散列函数)来获得几乎唯一的数字,&#34;指纹&#34;
这样,每次运行程序时,都会得到一个不同的值作为srand的种子。
由于种子不同,rand中的随机数序列也会不同。
答案 2 :(得分:0)
article in the link you reference认为无法保证您可以将time_t
转换为unsigned int
,time_t
依赖于实现,因此转为{{1}不是严格可移植的,但你需要一个unsigned int来播种srand。文章说:
问题是time_t是受限制的类型,可能无法有意义地转换为unsigned int。
建议的解决方案是对构成unsigned int
值的字节执行hash function,这样就不会出现可移植性问题。散列函数将输入的位序列映射到一个值,通常在特定范围内,在这种情况下,您希望将构成time_t
(sizeof time_t)的所有字节映射到unsigned int。良好的散列函数将具有avalanche effect,这意味着输入的微小变化(时间变化一秒)将对输出产生重大影响(输出位的一半翻转)。
关于代码的作用,它实现了一个散列函数,该函数遍历time_t的每个字节并将其添加到当前种子的产品(无符号大小的模数)乘以常量time_t
。此哈希函数是linear congruential generator。请注意,UCHAR_MAX + 2U
是指向无符号字符的指针,该字符用作为p
的存储别名的字符数组的基础。通常,由于strict aliasing rule,您不应该在C ++中执行此操作,但规则允许您将另一种类型别名为字符数组(有符号或无符号)。