简体   繁体   English

rand()不给我一个随机数(即使使用srand()时)

[英]rand() not giving me a random number (even when srand() is used)

Okay I'm starting to lose my mind. 好吧,我开始失去理智了。 All I want to do is random a number between 0 and 410, and according to this page, my code should do that. 我要做的只是随机选择一个介于0到410之间的数字,并且根据页面,我的代码应该这样做。 And since I want a random number and not a pseudo-random number, I'm using srand() as well, in a way that eg this thread told me to do. 而且由于我想要一个随机数而不是一个伪随机数,因此我也使用了srand(),例如, 线程告诉我这样做。 But this isn't working. 但这是行不通的。 All I get is a number that is depending on how long it was since my last execution. 我得到的只是一个数字,该数字取决于自上次执行以来的时间。 If I eg execute it again as fast as I can, the number is usually 6 numbers higher than the last number, and if I wait longer, it's higher, etc. When it reaches 410 it goes back to 0 and begins all over again. 如果我以最快的速度执行它,则该数字通常比上一个数字高6个数字,如果我等待更长的时间,则该数字更高,依此类推。等等。当达到410时,它将返回0,然后重新开始。 What am I missing? 我想念什么?

Edit: And oh, if I remove the srand(time(NULL)); 编辑:哦,如果我删除了srand(time(NULL)); line I just get the same number (41) every time I run the program. 每次我运行该程序时,我只会得到相同的数字(41)。 That's not even pseudo random, that's just a static number. 这甚至不是伪随机数,而只是一个静态数。 Just copying the first line of code from the article I linked to above still gives me number 41 all the time. 仅复制我上面链接的文章的第一行代码仍然始终使我获得41。 Am I the star in a sequel to "The Number 23", or have I missed something? 我是《 The Number 23》续集中的明星,还是错过了什么?

int main(void) {

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

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

    system("pause");

}

That is what you get for using deprecated random number generation. 那就是使用不推荐使用的随机数生成所得到的。

rand produces a fixed sequence of numbers (which by itself is fine), and does that very, very badly. rand产生一个固定的数字序列(本身就很好),并且这样做非常非常糟糕。

You tell rand via srand where in the sequence to start. 您通过srand告诉rand从何处开始。 Since your "starting point" (called seed btw) depends on the number of seconds since 1.1.1970 0:00:00 UTC, your output is obviously time depended. 由于您的“起点”(称为种子 btw)取决于自世界标准时间1.1.1970 0:00:00以来的秒数,因此您的输出显然取决于时间。

The correct way to do what you want to do is using the C++11 <random> library. 正确的方法是使用C ++ 11 <random>库。 In your concrete example, this would look somewhat like this: 在您的具体示例中,这看起来像这样:

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

auto random_number = dist(rng);

For more information on the evils of rand and the advantages of <random> have a look at this . 有关rand的弊端和<random>的优点的更多信息,请查看此内容

As a last remark, seeding std::mt19937 like I did above is not quite optimal because the MT's state space is much larger than the 32 bit you get out of a single call to std::random_device{}() . 最后一点,像我上面那样播种std::mt19937并不是十分理想,因为MT的状态空间比您从对std::random_device{}()的单次调用中获得的32位要大得多。 This is not a problem for toy programs and your standard school assignments, but for reference: Here is my take at seeding the MT's entire state space, plus some helpful suggestions in the answers. 对于玩具计划和您的标准学校作业来说,这不是问题,但仅供参考: 是我为MT的整个状态空间设定种子的方法,以及答案中的一些有用建议。

From manual: 从手册:

time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). 时间()返回时间的秒从epoch 1970-01-01 00:00:00 0000(UTC)的数量 ,。

Which means that if you start your program twice both times at the same second you will initialize srand with same value and will get same state of PRNG. 这意味着,如果您在同一秒两次启动程序两次,则将使用相同的值初始化srand,并获得相同的PRNG状态。

And if you remove initialization via call to srand you will always get exactly same sequence of numbers from rand . 而且,如果通过调用srand删除初始化,则始终会从rand获得完全相同的数字序列。

I'm afraid you can't get trully random numbers there. 恐怕您无法在那里获得真正的随机数。 Built in functions are meant to provide just pseudo random numbers. 内置函数旨在仅提供伪随机数。 Moreover using srand and rand, because the first uses the same approach as the second one. 而且使用srand和rand,因为第一种使用与第二种相同的方法。 If you want to cook true random numbers, you must find a correct source of entrophy, working for example with atmospheric noise, as the approach of www.random.org. 如果您想烹饪真实的随机数,则必须找到正确的来源,例如使用大气噪声,如www.random.org所示。

The problem here consists in the seed used by the randomness algorithm: if it's a number provided by a machine, it can't be unpredictable. 这里的问题在于随机性算法使用的种子:如果它是机器提供的数字,那么它是不可预测的。 A normal solution for this is using external hardware. 通常的解决方案是使用外部硬件。

Unfortunately you can't get a real random number from a computer without specific hardware (which is often too slow to be practical). 不幸的是,如果没有特定的硬件,您将无法从计算机中获得真实的随机数(这通常太慢而无法实用)。

Therefore you need to make do with a pseudo generator. 因此,你需要用的则是伪发电机。 But you need to use them carefully. 但是您需要仔细使用它们。

The function rand is designed to return a number between 0 and RAND_MAX in a way that, broadly speaking, satisfies the statistical properties of a uniform distribution. 设计函数rand是返回0到RAND_MAX之间的数字,从广义上讲,它满足均匀分布的统计属性。 At best you can expect the mean of the drawn numbers to be 0.5 * RAND_MAX and the variance to be RAND_MAX * RAND_MAX / 12 . 充其量您可以期望得出的平均值为0.5 * RAND_MAX ,方差为RAND_MAX * RAND_MAX / 12

Typically the implementation of rand is a linear congruential generator which basically means that the returned number is a function of the previous number. 通常, rand的实现是线性同余生成器 ,这基本上意味着返回的数字是先前数字的函数。 That can give surprisingly good results and allows you to seed the generator with a function srand . 这可以给效果出奇的好,并允许您与种子的函数发生器srand

But repeated use of srand ruins the statistical properties of the generator, which is what is happening to you: your use of srand is correlated with your system clock time. 但是 重复使用srand破坏生成器的统计属性,这就是您正在发生的事情:您对srand的使用与系统时钟时间相关。 The behaviour you're observing is completely expected. 您观察到的行为完全可以预期。

What you should do is to only make one call to srand and then draw a sequence of numbers using rand . 您应该做的只是只调用srand ,然后使用rand绘制数字序列。 You cannot easily do this in the way you've set things up. 您无法轻松完成设置。 But there are alternatives; 但是还有其他选择。 you could switch to a random number generator (say mersenne twister) which allows you to draw the (n)th term and you could pass the value of n as a command line argument. 您可以切换到随机数生成器(例如mersenne twister),该生成器允许您绘制第n个项,并且可以将n的值作为命令行参数传递。

As a final remark, I'd avoid using a modulus when drawing a number. 最后,我在绘制数字时会避免使用模数。 This will create a statistical bias if your modulo is not a multiple of RAND_MAX. 如果您的模数不是RAND_MAX的倍数,则会产生统计偏差。

Try by change the NULL in time(NULL) by time(0) (that will give you the current système time). 尝试通过更改time(0)中的time(NULL)中的NULL(这将为您提供当前系统时间)。 If it doesn't work, you could try to convert time(0) into ms by doing time(0)*1000. 如果它不起作用,则可以尝试通过执行time(0)* 1000将time(0)转换为ms。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM