C ++可预测的Rand()输出

时间:2013-06-29 23:14:29

标签: c++ random

在注意到rand()函数每次产生41的相同输出后,我使用srand(time(0))播种了生成器。这解决了重复输出的问题,但现在它给了我不断增加的数字。 (I.E. 245,248,250,253,255,256)。我可以理解,由于系统时间的影响,它正在增加,但这是正常的吗?

这是我的计划:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{

    int number;

    srand(time(0));

    cout << rand() % 1000;

    return 0;

}

我反复运行这个而不是循环。 多次试验的输出: 285 295 305 311 325 334 344 354 355

6 个答案:

答案 0 :(得分:5)

来自MS的C ++ rand()使用最简单的随机生成器Linear congruential generator

这是它的代码:

int __cdecl rand (
    void
    )
{
    _ptiddata ptd = _getptd();

    return( ((ptd->_holdrand = ptd->_holdrand * 214013L
        + 2531011L) >> 16) & 0x7fff );
}

因此,每当你为你的函数设定种子时,你只需设置第一个值(如果你快速运行你的程序,它会不时地增加一些单位)

现在,如果您插入rand()x+a的数学等式,其中x是上次调用函数的值,而a是自那次通话以来你的时间变化你会注意到: ((x + a)* 214013 + 2531011)&gt;&gt; 16 =(x * 214013 + 2531011 + a * 214013)&gt; 16

因为您运行程序的速度非常快。您的a05秒之间变化,让我们说。那么,当你将这个数字右移16位时,a*214013的最大值为1070065,最后得到的是16十进制数,这是近似很多你的新输出与你以前的输出不同(我说大约是因为你不能说(x * 214013 + 2531011 + a * 214013)&gt;&gt; 16 =(x * 214013 + 2531011&gt;&gt; 16)+( a * 214013&gt;&gt; 16)因为携带而来)

答案 1 :(得分:3)

这个错误每周大约出现一次:

如果您在调用rand()之前每次都致电srand(),那么您根本不会获得随机数,您将获得当时的哈希函数。在循环外调用srand() ONCE,ON ON ONCE,最好是在程序的最开始,然后根据需要多次调用rand()来获取值。

没有生成&#34;一个随机数&#34;。如果在一系列程序调用中需要随机数,则别无选择,只能在程序外生成这些随机数。一种方法是从/dev/urandom(在Linux上)或使用CryptGenRandom(在Windows上)读取。另一种选择是使用硬件或random.org等服务。

你拥有的发电机有多重要 - 如果你为每一次通话播种,你没有得到随机数,你就会获得种子值的哈希函数。如果您的种子值变化足够快,并且散列函数非常好,那可能已经足够好了 - 但它仍然没有使用RNG算法。

答案 2 :(得分:1)

我不知道你为什么会得到这些结果,但在C ++ 11中有更好的方法:

#include <random>
#include <iostream>
int main()
{
    auto rnd = std::default_random_engine(std::random_device{}());
    std::uniform_int_distribution<> dis(1, 999);
    std::cout << dis(rnd) << '\n';
}

答案 3 :(得分:0)

rand的工作方式是您需要遵循两条规则:

  1. 您必须先播种(srand)和
  2. 您不希望在每次调用rand之前播种它。你只需要在整个序列之前播种一次。
  3. 所以为了真正测试你,你的代码看起来应该更像这样:

    int main()
    {
        srand(time(0));
    
        // Output a sequence of 100 random numbers, each less than 1000
        for ( int i = 0; i < 100; i++ )    
            cout << rand() % 1000 << endl;
    
        return 0;
    }
    

    如果程序必要时每次运行仅输出一个随机数,并且程序每秒运行一次或多次,那么time(0)可能不是合适的种子。也许使用clock_gettime(3)会在几毫秒内为您提供更多内容。

答案 4 :(得分:0)

rand在运行时库中实现为线性同余生成器,其形式如下:

result = (seed * result + offset) % big_number

如果我们认为big_number是无限的并且您在t时间运行您的程序,那么

result = t * result + offset

如果您在很短的时间alpha之后再次运行该程序,那么

result = (t + alpha)* result + offset

如果运行时库使用较小的值初始化结果,则显示的结果将以alpha * result的小值递增。

用更高分辨率的计数器替换time()会大大改善这一点。例如,在x86上,rdtcs指令(通常作为编译器内部提供)几乎可以解决问题。

更好的解决方案是使用非线性同余生成器来种子rand(),就像Jesse Good建议的那样,也可以通过boost库在非c ++ 11编译器上使用。

如果可能的话,最好坚持使用c ++ 11随机生成器而不是c rand。

答案 5 :(得分:0)

我最近碰到了同样的问题,发现Karoly Horvath对你原来问题的评论解决了这个问题,虽然它有点“hacky”。我看到返回值有可预测的增加,并且在rand()之后立即粘贴另一个srand()后,问题就消失了。我最终得到了这个:

srand(time(NULL));
rand();
int seed = rand();

我想弄清楚为什么这种情况发生了......但与此同时这很有效。