Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C语言中的随机数发生器_C_Random - Fatal编程技术网

C语言中的随机数发生器

C语言中的随机数发生器,c,random,C,Random,我试图生成一个随机数0-59,但对C中的rand()函数不满意。下面是我正在使用的代码: #include <stdlib.h> #include <time.h> main() { int num; srand(time(NULL)); num = rand(); num = num % 59; printf("%d\n", num); } #包括 #包括 main() { int-num; srand(时间(空)); num=rand(); num=num%59

我试图生成一个随机数0-59,但对C中的rand()函数不满意。下面是我正在使用的代码:

#include <stdlib.h>
#include <time.h>

main()
{

int num;
srand(time(NULL));
num = rand();
num = num % 59;
printf("%d\n", num);
}
#包括
#包括
main()
{
int-num;
srand(时间(空));
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);
或者,如果您没有此功能:

// 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()保证返回[0…2**31)范围内的数字
#定义MAX_RANDOM((1(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);
    }
}
int main(无效)
{
int num,i;
srand(time(NULL));//种子一次

对于(i=0;i每次重新运行程序时,都会使用
time()
重新设定种子,该函数每秒只前进一次(如果重新运行程序速度足够快,则会得到相同的结果)

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

printf("%d\n", time(NULL) % 59);
我相信你会明白这是怎么回事

在这种情况下,如果使用“更正确的”rand()*59/rand_MAX
,这意味着从“更随机的”位中选择一个值,那么情况会更糟——结果可能在500秒或更长时间内根本不会改变

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


阅读
/dev/uradom
应该可以提供一个好的种子,在这种情况下,您不必担心混合,但是如果不这样做,多次调用
rand()
应该有助于消除您开始使用的低质量种子中特别引人注目的人工制品(当然,除了每秒只改变一次的问题).

哪里是
#包括
?不要使用
%
来限制伪随机数的范围:这里有另一种生成数字的方法,它似乎符合您的需要:不要尝试实现您自己的生成器。假设这是出于统计目的而不是为了加密,请在谷歌上搜索“Mersenne Twister”@pjs感谢Mersenne Twister的提醒。
%
的根本问题是它试图将2**n等概率珠装入60个桶中。
rand()/(double)rand_MAX*60
如何更好?@PascalCuoq不是吗?如果使用模除法,则得到0到
60之间的数字的机会是-(2**n%60)
更高。如果排除模运算,那么这个问题就不存在了,因为这个问题是由
2**n
不能被60整除这一事实引起的。好吧,
2**n
不能被60整除这一事实正是问题所在,而
/(双精度)RAND_MAX*60
您仍在以确定的方式将这些
2**n
等概率值发送到60个桶中。得到更多珠子的不是同一个桶,但从数学上讲,有些桶仍然得到更多珠子。@PascalCuoq我刚才遇到了什么?(如果是,我正在编辑我的答案。)是的。如果你一次得到2n个珠子,要平均装满60个桶,唯一的办法就是扔掉一些珠子,或者要求另一组2n个珠子,或者混合使用这两种方法。