我听说有人告诉我们rand()
的使用是不好的,即使使用srand()
来获得种子。为什么呢?我想知道这些事情是如何发生的...并为另一个问题感到抱歉..但是,对此有什么替代选择?
答案 0 :(得分:4)
这个故事分为两个部分。
首先,rand
是pseudorandom number generator。这意味着它取决于种子。对于给定的种子,它将始终给出相同的序列(假设实现相同)。这使其不适用于安全性非常重要的某些应用程序。 但是,这并非专门针对rand
。这是任何伪随机数生成器的问题。毫无疑问,存在许多类伪随机生成器可以接受的问题。真正的随机数生成器有其自身的问题(效率,实现,熵),因此对于与安全性无关的问题,通常使用伪随机数生成器。
因此,您分析了您的问题,然后得出了伪随机数生成器是解决方案。至此,我们了解了C随机库(包括rand
和srand
)的特定问题,这些问题专门针对该随机库并使它过时(又称:应该从不使用rand
和C随机库)。
一个问题是它具有全局状态(由srand
设置)。这使得不可能同时使用多个随机引擎。它还使多线程任务变得非常复杂。
最明显的问题是它缺少分发引擎:rand
为您提供了间隔[0 RAND_MAX]
中的一个数字。在此间隔中它是统一的,这意味着此间隔中的每个数字都有相同的出现概率。但是大多数情况下,您需要在特定时间间隔内使用随机数。假设[0, 1017]
。常用(且天真)的公式是rand() % 1018
。但这是一个问题,除非RAND_MAX
是1018
的精确倍数,否则您将不会获得均匀的分布。
另一个问题是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
-
srand
初始化RNG,以实现可重复的“随机性”。这两点加在一起,妨碍了实现改进RNG实现的能力(例如,使用加密的或“更好”的RNG)。例如,JavaScript的Math.random
和FreeBSD的arc4random
都没有此问题,因为它们不允许应用程序以可重复的“随机性”作为种子。V8JavaScript引擎正是出于这个原因能够将其Math.random
实现更改为xorshift128+
的变体,同时保持向后兼容。 (另一方面,如BCryptGenRandom
中那样,让应用程序为 supplement 随机性提供附加数据的问题较少;尽管如此,但这通常仅在加密RNG中可见。)< / p>
也:
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是一个非常棘手的主题。我对他们一无所知,但我相信专家。