为什么rand()在播种1和UINT_MAX时产生相同的值?

时间:2015-11-24 14:18:26

标签: c++ random srand

以下是一些代码:

#include <iostream>

int main() {
    srand(1);
    std::cout << rand() << "\n";
    srand(UINT_MAX);
    std::cout << rand() << "\n";
}

这会产生以下输出:

16807
16807

为什么这两个种子产生相同的结果?它们在连续rand()次调用中产生的整个值序列也是相同的。可能值的范围太大,不足以成为纯粹的巧合。是吗:

  • rand()的实施意外(如果是的话,我很好奇这可能是什么)
  • 按设计(如果是,为什么?)

(可能相关:种子10,100,1000,10000和100000分别产生168070,1680700,16807000,168070000和1680700000.)

5 个答案:

答案 0 :(得分:3)

已知

tl; dr: rand()那么糟糕。

实际值是实现定义的。我在我的平台上得到以下值:

seed:          1 : 41
seed: 4294967295 : 35
seed:         10 : 71
seed:        100 : 365
seed:       1000 : 3304
seed:      10000 : 32694

rand()可以依赖于随意的用户匆忙。它不适合其他任何东西。

实现通常使用低质量的生成器(最常见的是Linear Congruential with bad constants)。

所需的数值范围是0 ... 32767,虽然实施可能通常不会超过 - 但您可以预期许多种子会产生相同的值。

对于C ++ modern,请参阅<random>以获取可靠的选项。

答案 1 :(得分:3)

一个非常简单的可用随机数生成器是Lehmer number generator。这个RNG可能是最简单的在软件中实现的,它仍然可以使用,因此可能它具有最大的随机性问题,并且最容易分析。

数字16807(也就是7的五次幂)与Lehmer RNG有关,因为它用于1988年最早的实施之一 - 显然今天仍在使用!

第N个随机数的公式是(使用^进行求幂):

R(n) = (seed * (16807 ^ n)) mod (2 ^ 31 - 1)

如果设置seed = 1,则n = 1:

R(1) = 16807 mod (2 ^ 31 - 1) = 16807

如果您设置seed = 2 ^ 32 - 1

R(1) =
    (2 ^ 32 - 1) * 16807 ≡ (expressing 2^32 = 2^31 * 2)
    ((2 ^ 31 - 1) * 2 + 1) * 16807 ≡ (distributive law)
    (2 ^ 31 - 1) * 2 * 16807 + 1 * 16807 ≡ (modulo 2^31-1)
    16807

这里随机序列中第一个数字的相等性是因为Lehmer RNG中的模数几乎是2的幂(2^31-1),并且你的种子也几乎是2的幂({ {1}})。

种子= 2^32-1会发生同样的情况。

答案 2 :(得分:2)

这取决于您的随机数生成器的实现。 见What common algorithms are used for C's rand()? 用于常见的实现。

通常,可能的种子值的空间比UINT_MAX短得多。 可能是1和UINT_MAX映射到相同的内部种子。

通常Linear congruential generator用于rand(),然后第一个生成的随机数取决于

first_random_number  = (seed * const + another_const)  % third_constant

关于种子。这解释了你发现的依赖性。

答案 3 :(得分:0)

我没有看到为什么你观察到的不幸的相关性会被设计到你正在使用的rand的实现中的充分理由。根据您的建议,这很可能是意外实施。也就是说,我也认为这是巧合,你可以准确地与这些输入产生相关性。另一个实现可能有其他一组不幸的输入。

  如果是这样的话,我很好奇那可能是什么

如果您的实现是开源的,那么您可以通过阅读源代码找到答案。如果它是专有的,您仍然可以在某些文档中找到该算法的提及,或者如果您是客户,您可以询问实施者。

答案 4 :(得分:-3)

如上所述here如果seed设置为1,则将生成器重新初始化为其初始值,并生成与调用rand或srand 之前相同的值。

另请注意,使用相同种子的两个不同初始化将在后续调用rand时生成相同的连续结果。