我应该在 C 中为 erand48() 使用什么种子值



我是C编程的新手,我已经读到erand48((是线程安全随机数生成的一个不错的选择。但是,该函数的种子值为: 无符号短 int 数组[3]

关于此种子值应初始化为什么的任何建议?

好吧。因此,首先,让我明确指出,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定期将熵注入并刷新,确保您拥有相当随机的数字的可观供应。

只有我的 2 美分...

前段时间,我们在其中一个项目中使用了相同的函数系列。该产品必须在Windows/Unix上运行,所以我们没有使用/dev/random

相反,我们将 host_ip_addr + time(( + process_id + thread_id 连接为字符串,并从该字符串生成一个哈希。然后,我们将尾随字节 XOR 分散到 6 个前导字节上。我们使用最终数据作为种子...

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 位状态的数组(假设短值有 16 位,则为 3x16(。你可以用任何东西来播种它 - 只需获得 48 个随机位并将它们推入数组[3],来自/dev/urandom,来自 time/pid/whatever。

几个陷阱:- lcong48(( - 忘记它甚至存在- "我如何确保两个种子不会彼此靠近得离谱?"- 不要,只使用另一个 RNG 会花费更少的时间。

最新更新