在研究this question并阅读random.py
中的源代码时,我开始怀疑randrange
和randint
是否真的表现为“广告宣传”。我非常倾向于这么认为,但是我读它的方式,randrange
基本上实现为
start + int(random.random()*(stop-start))
(假设start
和stop
的整数值),因此randrange(1, 10)
应返回1到9之间的随机数。
randint(start, stop)
正在调用randrange(start, stop+1)
,从而返回1到10之间的数字。
我现在的问题是:
如果random()
曾要返回1.0
,那么randint(1,10)
会返回11
,不是吗?
答案 0 :(得分:27)
来自random.py
和文档:
"""Get the next random number in the range [0.0, 1.0)."""
)
表示间隔独占 1.0。也就是说,它永远不会返回1.0。
这是数学中的一般惯例,[
和]
是包容性的,而(
和)
是排他性的,两种类型的括号可以混合为(a, b]
或[a, b)
。请查看wikipedia: Interval (mathematics)以获得正式解释。
答案 1 :(得分:12)
其他答案指出,random()
的结果始终严格小于1.0
;然而,这只是故事的一半。
如果您将randrange(n)
计算为int(random() * n)
,那么 还需要知道任何满足x
的Python浮点0.0 <= x < 1.0
,以及任何正整数n
,0.0 <= x * n < n
都是如此,因此int(x * n)
严格小于n
。
这里有两件事可能出错:首先,当我们计算x * n
时,n
被隐式转换为浮点数。对于足够大的n
,该转换可能会改变该值。但是如果你看一下Python源代码,你会发现它只使用int(random() * n)
方法n
小于2**53
(这里和下面我假设平台使用IEEE 754双打),这是保证n
到浮点数的转换不会丢失信息的范围(因为n
可以完全表示为浮点数)。
可能出错的第二件事是乘法x * n
的结果(现在作为浮点数的产物执行,记得)可能不会完全可以表示,因此会有一些舍入参与其中。如果x
足够接近1.0
,则可以想到舍入会将结果四舍五入到n
本身。
要看到这种情况不会发生,我们只需要考虑x
的最大可能值,即(几乎所有运行Python的计算机上)1 - 2**-53
。因此,我们需要针对正整数(1 - 2**-53) * n < n
显示n
,因为random() * n <= (1 - 2**-53) * n
始终是真的。
证明(草图)让k
成为k
的唯一整数2**(k-1) < n <= 2**k
。然后,n
的下一个向下浮动为n - 2**(k-53)
。我们需要证明n*(1-2**53)
(即产品的实际,未包含的价值)更接近n - 2**(k-53)
而不是n
,因此它将始终向下舍入。但是一个小算术表明从n*(1-2**-53)
到n
的距离是2**-53 * n
,而从n*(1-2**-53)
到n - 2**(k-53)
的距离是(2**k - n) * 2**-53
。但2**k - n < n
(因为我们选择了k
以便2**(k-1) < n
),因此产品 更接近n - 2**(k-53)
,因此将< / em>向下舍入(假设,即平台正在做某种形式的舍入到最近)。
所以我们很安全。呼!
附录(2015-07-04):以上假设采用IEEE 754二进制64算法,采用圆形连接到均匀舍入模式。在许多机器上,这种假设是相当安全的。但是,在使用x87 FPU进行浮点运算的x86机器上(例如,32位Linux的各种风格),乘法中有double rounding的可能性,这使得{{1}成为可能在random() * n
返回最大可能值的情况下,将向上舍入到n
。可能发生这种情况的最小random()
是n
。有关详情,请参阅http://bugs.python.org/issue24546上的讨论。
答案 2 :(得分:3)
来自Python文档:
几乎所有模块函数都依赖于函数random(),它在半开放范围[0.0,1.0]内均匀生成随机浮点数。
几乎每个PRNG的浮点数......