我是C编程的新手,我已经读过,对于线程安全的随机数生成来说,erand48()是一个不错的选择。但是该函数采用的种子值为:unsigned short int array [3]
有关应将此种子值初始化为什么的任何建议?
答案 0 :(得分:2)
好的。首先,让我明确指出libc
中的PRNG是确定性的(这就是为什么它需要种子),使用LCG - 这意味着它很容易预测所有一旦你有一些价值观,因此是不安全的。
现在。 erand48()
从伪随机实数的均匀分布返回double
大小的随机浮点值。它本身并不取种子值,而是要求您提供状态缓冲区。这是完整的声明:
double erand48(unsigned short xsubi[3]);
有趣的是,状态缓冲区必须以随机值播种,以便生成器工作。我的第一个想法是从/dev/urandom
读取。
我们可以用这样的东西做到这一点(使用无缓冲的读取来防止这些小读取的浪费):
#include <stdio.h>
#include <stdlib.h>
void *thread_f (void *i) {
// setup unbuffered urandom
urandom = fopen ("/dev/urandom", "r");
setvbuf (urandom, NULL, _IONBF, 0); // turn off buffering
// setup state buffer
unsigned short randstate[3];
// fgetc() returns a `char`, we need to fill a `short`
randstate[0] = (fgetc (urandom) << 8) | fgetc (urandom);
randstate[1] = (fgetc (urandom) << 8) | fgetc (urandom);
randstate[2] = (fgetc (urandom) << 8) | fgetc (urandom);
// cleanup urandom
fclose (urandom);
// you can now use erand48 (randstate);
... // do whatever work you need to do
return result;
}
这是线程安全的,甚至可以确保所有线程的相对安全的种子值。
当然,如果速度不是太大的问题(即:你可以忍受很小的速度)并且你可以使用整数,那么直接从/dev/urandom
进行无缓冲读取是完美的解决方案。更好的是,/ dev / urandom提供安全,不可预测的伪随机整数(技术上,一个字节流,但只要匹配大小,它们将始终作为整数),这些整数通常也是均匀分布的。
另外,/dev/urandom
会定期将熵注入其中并进行刷新,以确保您拥有相当随机的数字。
答案 1 :(得分:1)
只是我的2美分......
我们之前的一个项目中使用了相同的函数系列。该产品必须在Windows / Unix上运行,因此我们没有使用 / dev / random 。
相反,我们将 host_ip_addr + time()+ process_id + thread_id 连接成一个字符串,并从该字符串生成一个哈希值。然后,我们将尾随字节XOR传送到6个前导字节。我们用最终数据作为种子...
答案 2 :(得分:0)
rand48系列是48位LCG,意思是
double erand48(uint48_t *state) {
*state = *state * A + C; /* A and C are suitable values */
return *state / 281474976710656.0; /* that's 2^48 */
}
...除了我从未见过具有uint48_t的计算机,所以你传递的是一个48位状态的数组(3x16假设一个短的16位)。 你可以用任何东西播种它 - 只需获得48个随机位并将它们从/ dev / urandom中推送到数组[3]中,从时间/ pid /中提取。
一些陷阱: - lcong48() - 忘了它甚至存在 - &#34;我怎样才能确保两颗种子彼此之间并不可笑呢?&#34; - 不要,只需使用另一个rng就可以花更少的时间。