C中的随机数发生器

我正在尝试生成0到59的随机数,并且对C中的rand()函数不满意。这是我正在使用的代码:

#include  #include  main() { int num; srand(time(NULL)); num = rand(); num = num % 59; printf("%d\n", num); } 

我已经重复了这段代码的运行,并注意到生成的随机数似乎并不是随机的。 生成的数字肯定是遵循一种模式,因为每次运行程序时,数字会逐渐变大,直到它回绕到开头(即2,17,21,29,38,47,54,59,4, 11 ….等)。

有没有一种方法可以使函数播种,这样每次重新运行函数时,我得到一个真正的随机数,生成的概率为1/60? 或者是否有任何替代方法我可以自己实现而不是在C中使用rand()函数?

有没有一种方法可以使函数播种,这样每次重新运行函数时,我都会获得一个真正的随机数

不,C标准库使用PRNG(伪随机数生成器)。 你永远不会得到真正的随机数。

但是,您可以使用比time()更频繁更改的内容来播种它,例如,在POSIX上:

 struct timeval tm; gettimeofday(&tm, NULL); srandom(tm.tv_sec + tm.tv_usec * 1000000ul); 

此外,使用模运算符生成随机数不是一个好的解决方案(它会严重降低熵)。 如果您有BSD样式的libc实现,请使用

 uint32_t n = arc4random_uniform(60); 

或者,如果您没有此function:

 // random() is guaranteed to return a number in the range [0 ... 2 ** 31) #define MAX_RANDOM ((1 << 31) - 1) long n; do { n = random(); } while (n > (MAX_RANDOM - ((MAX_RANDOM % 60) + 1) % 60)); n %= 60; 

注意使用random() – 它优于rand() (它有许多低质量的实现)。 可以使用srandom()播种此函数。

或者是否有任何替代方法我可以自己实现而不是在C中使用rand()函数?

你当然可以(当然,C库实现的编写者会怎么做呢?),但你最好不要 – 这是一个单独的科学来写一个好的PRNG,所以说。

编写程序的方式,每次都必须重新运行它以获得一个新的随机数,这也意味着每次都重新播种。 重新种植PRNG是不好的

你想种子一次 ,然后生成一堆随机数。

这样做:

 int main(void) { int num, i; srand(time(NULL)); // Seed ONCE for(i=0; i<100; ++i) // Loop 100 times for random numbers { num = rand(); num = num % 59; printf("%d\n", num); } } 

现在你应该得到更好的结果。

每次重新运行程序时,都会使用time()重新播种,并且该函数每秒只会前进一次(如果您足够快地重新运行程序,则会获得相同的结果)。

它似乎在它翻转之前递增的事实表明对rand()的第一次调用返回未修改的种子 – 该数字每秒递增一次。 在这种情况下,您将获得与运行时相同的结果(或非常相似的结果):

 printf("%d\n", time(NULL) % 59); 

我相信你可以看出它有什么问题。

在这种情况下,如果你使用’更正确’的rand() * 59 / RAND_MAX ,这意味着更喜欢“更随机”位的值,你会有更糟糕的情况 – 结果不会改变总共可能持续500秒或更长时间。

从根本上说,你需要找到一个不太可预测的种子,但你可能还希望在使用它之前看到它已正确混合。

/dev/urandom读取应该提供一个好的种子,在这种情况下你不需要担心混合,但是否则多次调用rand()应该有助于消除低质量的特别明显的文物你开始的种子(当然,除了它每秒只改变一次的问题)。