6

所以我正在测试计算某些掷骰子的概率,以进行游戏。如果滚动一个 10 面模具,则为基本情况。

我做了一百万个样本,最终得到以下比例:

Result
0       0.000000000000000%
1       10.038789961210000%
2       10.043589956410000%
3       9.994890005110000%
4       10.025289974710000%
5       9.948090051909950%
6       9.965590034409970%
7       9.990190009809990%
8       9.985490014509990%
9       9.980390019609980%
10      10.027589972410000%

当然,这些都应该是 10%。这些结果的标准偏差为 0.0323207%。在我看来,这似乎相当高。这只是巧合吗?据我了解,随机模块访问正确的伪随机数。即通过统计测试的方法是随机的。或者是这些伪伪随机数生成器

我应该使用加密伪随机数生成器吗?我相当确定我不需要真正的随机数生成器(参见http://www.random.org/http://en.wikipedia.org/wiki/Hardware_random_number_generator)。

我目前正在用 10 亿个样本重新生成所有结果,(因为为什么不呢,我有一个松脆的服务器可供我使用,还有一些睡眠要做)

4

6 回答 6

17

random模块文档

几乎所有的模块函数都依赖于基本函数random(),它在半开范围[0.0, 1.0)内均匀地生成一个随机浮点数。Python 使用 Mersenne Twister 作为核心生成器。它产生 53 位精度浮点数,周期为 2**19937-1。C 中的底层实现既快速又线程安全。Mersenne Twister 是现有测试最广泛的随机数生成器之一。但是,由于是完全确定性的,它并不适合所有用途,并且完全不适合加密用途。

来自关于 Mersenne Twister 的维基百科文章

它提供了快速生成非常高质量的伪随机数,专门设计用于纠正旧算法中发现的许多缺陷。

如果您有一个特定于操作系统的随机源,可通过 获得os.urandom(),那么您可以改用random.SystemRandom()该类。大多数random模块函数都可用作该类的方法。它可能更适合加密目的,再次引用文档:

返回的数据对于加密应用程序来说应该是不可预测的,尽管它的确切质量取决于操作系统的实现。

Python 3.6 添加了一个带有便捷方法的secrets模块来生成适用于加密目的的随机数据:

secrets模块用于生成适用于管理密码、帐户身份验证、安全令牌和相关机密等数据的加密强随机数。

特别是,secrets应该优先使用random模块中的默认伪随机数生成器,该生成器是为建模和模拟而设计的,而不是安全或密码学。

于 2012-08-28T17:18:01.383 回答
4

我用十亿次迭代重新运行了 OP 的练习:

from collections import Counter
import random
n = 1000000000
c = Counter(random.randint(1, 10) for _ in xrange(n))
for i in range(1,11):
    print '%2s  %02.10f%%' % (i, c[i] * 100.0 / n)

这是(重新格式化的)结果:

 1     9.9996500000%
 2    10.0011089000%
 3    10.0008568000%
 4    10.0007495000%
 5     9.9999089000%
 6     9.9985344000%
 7     9.9994913000%
 8     9.9997877000%
 9    10.0010818000%
10     9.9988307000%

请参阅此问题的其他答案以获得出色的分析。

于 2012-08-28T18:55:38.723 回答
3

Martijn 的回答非常简洁地回顾了 Python 可以访问的随机数生成器。

如果您想查看生成的伪随机数据的属性,请random.ziphttp://www.fourmilab.ch/random/下载,然后在大量随机数据样本上运行它。特别是 χ²(卡方)检验对随机性非常敏感。对于真正随机的序列,来自 χ² 检验的百分比应该在 10% 到 90% 之间。

对于一个游戏,我猜 Python 内部使用的 Mersenne Twister 应该是足够随机的(除非你正在建立一个在线赌场:-)。

如果您想要随机性,并且您使用的是 Linux,则可以从/dev/random. 这只会从内核的熵池(从中断到达的不可预测的时间收集)中产生随机数据,因此如果您用尽它,它将阻塞。此熵用于初始化(种子)由/dev/urandom. 在 FreeBSD 上,提供数据的 PRNG/dev/random使用 Yarrow 算法,该算法通常被认为是加密安全的。

编辑:我对来自random.randint. 首先创建一百万个随机字节:

import random
ba = bytearray([random.randint(0,255) for n in xrange(1000000)])
with open('randint.dat', 'w+') as f:
    f.write(ba)

然后我运行Fourmilabent的程序:

Entropy = 7.999840 bits per byte.

Optimum compression would reduce the size
of this 1000000 byte file by 0 percent.

Chi square distribution for 1000000 samples is 221.87, and randomly
would exceed this value 93.40 percent of the times.

Arithmetic mean value of data bytes is 127.5136 (127.5 = random).
Monte Carlo value for Pi is 3.139644559 (error 0.06 percent).
Serial correlation coefficient is -0.000931 (totally uncorrelated = 0.0).

现在对于 χ² 检验,距离 50% 越远,数据越可疑。如果一个非常挑剔,值 <10% 或 >90% 被认为是不可接受的。约翰沃克,作者ent称这个值“几乎是可疑的”。

作为对比,这里是我之前运行的来自 FreeBSD 的 Yarrow prng 的 10 MiB 的相同分析:

Entropy = 7.999982 bits per byte.

Optimum compression would reduce the size
of this 10485760 byte file by 0 percent.

Chi square distribution for 10485760 samples is 259.03, and randomly
would exceed this value 41.80 percent of the times.

Arithmetic mean value of data bytes is 127.5116 (127.5 = random).
Monte Carlo value for Pi is 3.139877754 (error 0.05 percent).
Serial correlation coefficient is -0.000296 (totally uncorrelated = 0.0).

虽然其他数据似乎没有太大差异,但 χ² 百分比接近 50%。

于 2012-08-28T18:00:41.677 回答
2

是的,出于所有实际目的,它在统计上是随机的。您看到的随机变化是完全正常的。事实上,如果它没有这样的变化,那将是一个糟糕的 rng。

由于 prng 的周期是 2**19937-1,因此在看到非随机分布之前,您需要生成比宇宙中的原子更多的数字。请注意,如果您生成 623 维向量,它会很快变得非随机。

于 2012-08-28T17:18:37.493 回答
1

在良好的 PRNG 中随机数出现不完美分布确实是正常的。但是,您生成的数字越多,您看到的数字就越少。

顺便说一句,我得到的标准偏差为 0.03066,略低于您给出的值。

于 2012-08-28T18:14:48.140 回答
1

这些结果非常接近您的预期,您可以通过简单的计算来检查这一点。如果您掷出 1,000,000 个 D10 并计算 1 的数量(例如),该随机变量的平均值为 100,000(试验次数 * 成功概率),方差为 90,000(试验次数 * 成功概率 * 失败概率),所以标准差是 sqrt(90,000)=300。因此,您应该期望从 100,000 得到大约 300,即 10% +/- 0.03%。

于 2016-12-13T11:05:12.233 回答