其他答案指出,结果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)
方法(这里和下面我假设平台使用 IEEE 754 双精度),这是转换为浮点数的范围保证不会丢失信息(因为可以精确地表示为浮点数)。n
2**53
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)
所以我们是安全的。呸!
附录(2015-07-04):以上假设 IEEE 754 binary64 算术,具有round-ties-to-even舍入模式。在许多机器上,这种假设是相当安全的。但是,在使用 x87 FPU 进行浮点运算的 x86 机器上(例如,各种风格的 32 位 Linux),在乘法中可能会进行双舍入,这使得在这种情况下可以向上random() * n
舍入where返回最大的可能值。可能发生这种情况的最小的情况是. 有关更多信息,请参阅http://bugs.python.org/issue24546上的讨论。n
random()
n
n = 2049