random.randint(1,10)可以返回11吗?

Tim*_*ker 10 python random bounds

当用于研究这个问题,并在阅读源代码random.py,我就开始琢磨是否randrangerandint真正表现为"广告".我非常倾向于这么认为,但我读它的方式randrange基本上是实现的

start + int(random.random()*(stop-start))
Run Code Online (Sandbox Code Playgroud)

(假设为start和的整数值stop),因此randrange(1, 10)应返回1到9之间的随机数.

randint(start, stop)正在呼叫randrange(start, stop+1),从而返回1到10之间的数字.

我现在的问题是:

如果random()再回来1.0,那么randint(1,10)会回来11,不是吗?

aio*_*obe 27

来自random.py和文档:

"""Get the next random number in the range [0.0, 1.0)."""
Run Code Online (Sandbox Code Playgroud)

)指示的时间间隔为独占 1.0.也就是说,它永远不会返回1.0.

这是数学中的一般惯例,[并且]是包容性的,(而且)是排他性的,并且两种类型的括号可以混合为(a, b][a, b).看一下维基百科:Interval(数学)的正式解释.

  • 这还不够,因为`0.0 <= x <1.0`暗示浮点运算中的'0 <= x*n <n`并不明显:通常,乘法的结果不会是完全可以表示,所以它将被舍入.它可以被四舍五入.**可以想象*这种舍入可以产生`n`,因为`x'非常接近(但不等于)`1.0`.幸运的是,有可能表明,假设从最接近,这种情况永远不会发生. (5认同)

Mar*_*son 12

其他答案指出,结果random()总是严格小于1.0; 然而,这只是故事的一半.

如果你计算randrange(n)int(random() * n),你需要知道,任何Python的浮动x满意0.0 <= x < 1.0,并任意正整数n,这是事实,0.0 <= x * n < n,使int(x * n)严格小于n.

这里有两件事可能会出错:首先,当我们计算时x * n,n会隐式转换为浮点数.足够大n,该转换可能会改变该值.但是如果你看一下Python源码,你会发现它只使用小于的int(random() * n)方法(这里和下面我假设平台使用IEEE 754双倍),这是转换为浮点数的范围保证不会丢失信息(因为可以完全表示为浮点数).n2**53nn

可能出错的第二件事是乘法的结果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.那么接下来的浮动从下nn - 2**(k-53).我们需要证明n*(1-2**53)(即产品的实际,圆唇,值)更接近n - 2**(k-53)n,所以它永远被舍去.但有点算术显示,从远处n*(1-2**-53)n2**-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),所以它得到四舍五入(假设,即,该平台是做某种形式的舍入到最近的).

所以我们很安全.唷!


附录(2015-07-04):上面假设IEEE 754二进制64算术,具有圆形到均匀的舍入模式.在许多机器上,这种假设是相当安全的.不过,在使用的x87 FPU浮点的x86机器(例如,32位Linux的各种口味的),还有的可能性双舍入的乘法,这使得它有可能random() * nn的情况下其中random()返回最大可能值.n这可能发生的最小的是n = 2049.有关更多信息,请参阅http://bugs.python.org/issue24546上的讨论.