rand()没有给我一个随机数(即使使用srand())

时间:2015-01-12 14:04:25

标签: c++ random srand

好吧,我开始失去理智。我想做的只是随机的0到410之间的数字,根据this页面,我的代码应该这样做。因为我想要一个随机数而不是伪随机数,所以我也使用srand(),例如this线程告诉我这样做。但这不起作用。我得到的只是一个数字,取决于我上次执行以来的时间。如果我尽可能快地执行它,数字通常比最后一个数字高6个数字,如果我等待更长时间,它会更高,等等。当它达到410时,它会回到0并重新开始。我错过了什么?

编辑:哦,如果我删除srand(time(NULL));行,我每次运行程序时都得到相同的数字(41)。这甚至不是伪随机的,这只是一个静态数字。只是从the article I linked to above复制第一行代码仍然会给我41号码。我是“23号”续集中的明星,还是我错过了什么?

int main(void) {

    srand(time(NULL));
    int number = rand() % 410;

    std::cout << number << std::endl;

    system("pause");

}

5 个答案:

答案 0 :(得分:6)

这就是使用弃用的随机数生成所得到的。

rand产生一个固定的数字序列(这本身就很好),而且非常非常糟糕。

您可以通过rand告诉srand序列中的哪个位置。因为你的起点&#34; (称为种子 btw)取决于自1.1.1970 0:00:00 UTC以来的秒数,您的输出显然是时间依赖的。

执行您想要执行的操作的正确方法是使用C ++ 11 <random>库。在您的具体示例中,这看起来有点像这样:

std::mt19937 rng (std::random_device{}());
std::uniform_int_distribution<> dist (0, 409);

auto random_number = dist(rng);

有关rand邪恶的更多信息以及<random>的优势,请查看this

作为最后一句话,像我上面所做的那样播种std::mt19937并不是最理想的,因为MT的状态空间远远大于你通过{{1}的单个调用得到的32位}。这对于玩具程序和您的标准学校作业来说不是问题,但作为参考:Here是我对MT整个州空间播种的看法,以及答案中的一些有用建议。

答案 1 :(得分:1)

来自手册:

  

time()返回自Epoch以来秒数的时间,   1970-01-01 00:00:00 +0000(UTC)。

这意味着如果您在同一秒内两次启动程序两次,您将使用相同的值初始化srand并获得相同的PRNG状态。

如果您通过调用srand删除初始化,您将始终从rand获得完全相同的数字序列。

答案 2 :(得分:0)

我担心你不能在那里得到真正的随机数字。内置函数旨在提供伪随机数。另外使用srand和rand,因为第一个使用与第二个相同的方法。如果你想煮真正的随机数,你必须找到一个正确的熵来源,例如与大气噪声一起工作,作为www.random.org的方法。

这里的问题在于随机性算法使用的种子:如果它是机器提供的数字,它就不可能是不可预测的。一个正常的解决方案是使用外部硬件。

答案 3 :(得分:0)

不幸的是,如果没有特定的硬件(通常太慢而不实用),你就无法从计算机上获得真正的随机数。

因此,您需要使用伪生成器 make 。但是你需要仔细使用它们。

函数rand旨在以一种广义上满足均匀分布的统计特性的方式返回介于0和RAND_MAX之间的数字。最多可以预期绘制数字的平均值为0.5 * RAND_MAX,方差为RAND_MAX * RAND_MAX / 12

通常rand的实现是线性同余生成器,这基本上意味着返回的数字是前一个数字的函数。这可以给出令人惊讶的好结果,并允许您使用函数srand 种子生成

但是 重复使用srand会破坏生成器的统计属性,这就是您发生的事情:您对srand的使用与您的系统时钟时间相关。你正在观察的行为是完全可以预期的。

您应该只对srand进行一次调用,然后使用rand绘制一系列数字。你不能像你设定的那样轻松地做到这一点。但也有其他选择;你可以切换到一个随机数生成器(比如mersenne twister),它允许你绘制第(n)个术语,你可以将n的值作为命令行参数传递。

作为最后的评论,我在绘制数字时避免使用模数。如果您的模数不是RAND_MAX的倍数,这将产生统计偏差。

答案 4 :(得分:-3)

尝试通过时间(0)更改时间中的NULL(NULL)(这将为您提供当前的système时间)。如果它不起作用,你可以尝试通过执行时间(0)* 1000将时间(0)转换为ms。