为什么使用rand()被认为是不好的?

时间:2018-10-18 07:38:10

标签: c++ random lcg

我听说有人告诉我们rand()的使用是不好的,即使使用srand()来获得种子。为什么呢?我想知道这些事情是如何发生的...并为另一个问题感到抱歉..但是,对此有什么替代选择?

6 个答案:

答案 0 :(得分:4)

这个故事分为两个部分。

首先,randpseudorandom number generator。这意味着它取决于种子。对于给定的种子,它将始终给出相同的序列(假设实现相同)。这使其不适用于安全性非常重要的某些应用程序。 但是,这并非专门针对rand。这是任何伪随机数生成器的问题。毫无疑问,存在许多类伪随机生成器可以接受的问题。真正的随机数生成器有其自身的问题(效率,实现,熵),因此对于与安全性无关的问题,通常使用伪随机数生成器。

因此,您分析了您的问题,然后得出了伪随机数生成器是解决方案。至此,我们了解了C随机库(包括randsrand)的特定问题,这些问题专门针对该随机库并使它过时(又称:应该从不使用rand和C随机库)。

  • 一个问题是它具有全局状态(由srand设置)。这使得不可能同时使用多个随机引擎。它还使多线程任务变得非常复杂。

  • 最明显的问题是它缺少分发引擎rand为您提供了间隔[0 RAND_MAX]中的一个数字。在此间隔中它是统一的,这意味着此间隔中的每个数字都有相同的出现概率。但是大多数情况下,您需要在特定时间间隔内使用随机数。假设[0, 1017]。常用(且天真)的公式是rand() % 1018。但这是一个问题,除非RAND_MAX1018的精确倍数,否则您将不会获得均匀的分布。

  • 另一个问题是rand的实现质量。这里还有其他答案比我能更好地详细说明,因此请阅读它们。

在现代C ++中,您绝对应该使用<random>中的C ++库,它带有多个随机定义良好的引擎(用于整数和浮点类型)和各种发行版。

答案 1 :(得分:3)

这里没有任何答案说明rand() 不好的真正原因。

rand()pseudo-random number generator (PRNG),但这并不意味着它一定很糟糕。实际上,有非常好的PRNG,从统计上讲很难或不可能与真实的随机数区分开来。

rand()完全由实现定义,但从历史上看,它是作为Linear Congruential Generator (LCG)实现的,通常是PRNG的快速类,但臭名昭著。这些生成器的较低位比较高位具有较低的统计随机性,并且生成的数字可以生成可见的晶格和/或平面结构(最好的示例是著名的RANDU PRNG)。一些实现尝试通过将位右移预定义的数量来减少低位问题,但是这种解决方案也缩小了输出范围。

仍然有出色LCG的显着示例,例如Pierre L'Ecuyer的不同大小和良好晶格结构的线性同余生成器表中介绍的L'Ecuyer的64位和128位乘法线性同余生成器。 / em>。

一般的经验法则是,不信任rand(),请使用适合您需要和使用要求的伪随机数生成器。

答案 2 :(得分:3)

rand / srand的坏处在于rand

  • 使用未指定的RNG算法,但
  • 允许使用srand初始化RNG,以实现可重复的“随机性”。

这两点加在一起,妨碍了实现改进RNG实现的能力(例如,使用加密的或“更好”的RNG)。例如,JavaScript的Math.random和FreeBSD的arc4random都没有此问题,因为它们不允许应用程序以可重复的“随机性”作为种子。V8JavaScript引擎正是出于这个原因能够将其Math.random实现更改为xorshift128+的变体,同时保持向后兼容。 (另一方面,如BCryptGenRandom中那样,让应用程序为 supplement 随机性提供附加数据的问题较少;尽管如此,但这通常仅在加密RNG中可见。)< / p>

也:

  • RNG算法和播种过程未指定的事实意味着rand / srand实现,between versions of the same standard library,操作系统之间,甚至保证了可重现的“随机性” 。
  • 如果在srand之前没有调用rand,则rand的行为类似于第一次调用srand(1)时的行为。实际上,这意味着rand只能实现为PRNG而不是不确定的RNG,并且rand的PRNG算法在给定的实现中无论应用程序是否调用{{ 1}}。

答案 3 :(得分:2)

首先,srand()没有种子,而是设置了种子。播种是任何伪随机数生成器(PRNG)使用的一部分。当种子播种时,PRNG从该种子产生的数字序列是严格确定性的,因为(大多数?)计算机无法生成真正的随机数。更改PRNG不会阻止序列从种子开始重复,这确实是一件好事,因为产生相同序列的伪随机数的功能通常很有用。

因此,如果所有PRNG与rand()共享此功能,为什么rand()被认为是不好的?好吧,它归结为伪随机的“伪”部分。我们知道PRNG不能真正是随机的,但我们希望它的行为尽可能接近真实的随机数生成器,并且可以使用various tests来检查PRNG序列与某个随机数生成器的相似度。真正的随机序列。尽管标准未指定其实现方式,但是在每个常用的编译器中,rand()都使用了非常老的生成方法,适用于非常弱的硬件,并且在这些测试中生成的结果相当差。自从这段时间以来,已经创建了许多更好的随机数生成器,最好选择一种适合您的需求,而不是依靠rand()可能会提供的劣质生成器。

哪种类型适合您的用途取决于您的工作,例如,您可能需要加密质量或多维生成,但是对于许多用途,您只是希望事物具有相当均匀的随机性,快速生成和金钱根据您可能希望xoroshiro128+生成器的结果质量而不同。另外,您可以使用C ++ <random>标头中的一种方法,但是提供的生成器不是最新技术,现在可以使用的更好,但是,它们对于大多数用途仍然足够好,非常方便。 / p>

如果有钱可以赚钱(例如在线赌场中的洗牌等),或者您需要加密的质量,则需要仔细研究合适的生成器,并确保它们完全符合您的特定需求。

答案 4 :(得分:0)

如果使用rand(),则在生成随机数后,您基本上会得到相同的结果。 因此,即使在使用srand()之后,如果有人可以猜测您使用的种子,也很容易预测生成的数字。这是因为函数rand()使用特定的算法来产生此类数字

在浪费时间的情况下,您可以找出在给定种子的情况下如何预测函数生成的数字。您现在只需要猜测种子即可。有人将种子称为当前时间。因此,如果可以猜测您运行应用程序的时间,我将能够预测该数字

不能使用RAND()!!!!

答案 5 :(得分:0)

rand通常是-但并非总是如此-由于历史原因,它是非常糟糕的pseudo-random number generator(PRNG)。具体实现有多糟。

C ++ 11具有更好的PRNG。使用其<random> standard header。尤其要注意std::uniform_int_distribution here,它在std::mersenne_twister_engine上方有一个很好的例子。

PRNG是一个非常棘手的主题。我对他们一无所知,但我相信专家。