random.randint(1,10) 能返回 11 吗?
在研究这个问题并阅读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
,不是吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
来自
random.py
和文档:)
表示间隔不包含 1.0。也就是说,它永远不会返回1.0。这是数学中的一般约定,
[
和]
包含在内,而(
和)
排除,并且两种类型的括号可以混合使用,如(a, b]
或[a, b)
。查看维基百科:间隔(数学)以获得正式解释。From
random.py
and the docs:The
)
indicates that the interval is exclusive 1.0. That is, it will never return 1.0.This is a general convention in mathematics,
[
and]
is inclusive, while(
and)
is exclusive, and the two types of parenthesis can be mixed as(a, b]
or[a, b)
. Have a look at wikipedia: Interval (mathematics) for a formal explanation.其他答案指出,
random()
的结果始终严格小于1.0
;然而,这只是故事的一半。如果您将
randrange(n)
计算为int(random() * n)
,您还需要知道对于任何 Python 浮点数x
满足0.0 <= x
1.0
,以及任何正整数n
,则0.0 <= x * n
0.0 <= x * n
n
,因此int(x * n)
严格小于n
。这里有两件事可能会出错:首先,当我们计算 x * n 时,n 被隐式转换为浮点数。对于足够大的
n
,该转换可能会改变该值。但如果您查看 Python 源代码,您会发现它仅对小于2* 的
(这里和下面我假设该平台使用 IEEE 754 双精度),这是n
使用int(random() * n)
方法*53n
转换为浮点数保证不会丢失信息的范围(因为n
可以精确地表示为浮点数)。第二个可能出错的事情是乘法 x * n 的结果(记住,它现在作为浮点数的乘积执行)可能无法完全表示,因此会有涉及一些舍入。如果
x
足够接近1.0
,可以想象舍入会将结果向上舍入到n
本身。为了确保这种情况不会发生,我们只需要考虑
x
的最大可能值,即(在几乎所有运行 Python 的机器上)1 - 2**-53
。所以我们需要证明(1 - 2**-53) * n
(1 - 2**-53) * n
(1 - 2**-53) * n
(1 - 2**-53) * n
n
表示正整数n
,因为random() * n <= (1 - 2**-53) * n
始终为真代码>.证明(草图)令
k
为唯一整数k
,使得2**(k-1)
2**(k-1)
2**(k-1)
。那么从k
n <= 2**kn
向下的下一个浮动是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 - 2**(k-53)
,因此它将向下舍入(假设平台正在进行某种形式的舍入-最近的)。所以我们很安全。唷!
附录 (2015-07-04):上面假设 IEEE 754 二进制 64 算法,采用舍入到偶数舍入模式。在许多机器上,这种假设是相当安全的。但是,在使用 x87 FPU 进行浮点运算的 x86 计算机上(例如,各种版本的 32 位 Linux),可能会出现 乘法中的双舍入,这使得
random() * n
可以向上舍入到n
在random()
返回最大可能值的情况下。可能发生这种情况的最小n
是n = 2049
。有关更多信息,请参阅 http://bugs.python.org/issue24546 上的讨论。Other answers have pointed out that the result of
random()
is always strictly less than1.0
; however, that's only half the story.If you're computing
randrange(n)
asint(random() * n)
, you also need to know that for any Python floatx
satisfying0.0 <= x < 1.0
, and any positive integern
, it's true that0.0 <= x * n < n
, so thatint(x * n)
is strictly less thann
.There are two things that could go wrong here: first, when we compute
x * n
,n
is implicitly converted to a float. For large enoughn
, that conversion might alter the value. But if you look at the Python source, you'll see that it only uses theint(random() * n)
method forn
smaller than2**53
(here and below I'm assuming that the platform uses IEEE 754 doubles), which is the range where the conversion ofn
to a float is guaranteed not to lose information (becausen
can be represented exactly as a float).The second thing that could go wrong is that the result of the multiplication
x * n
(which is now being performed as a product of floats, remember) probably won't be exactly representable, so there will be some rounding involved. Ifx
is close enough to1.0
, it's conceivable that the rounding will round the result up ton
itself.To see that this can't happen, we only need to consider the largest possible value for
x
, which is (on almost all machines that Python runs on)1 - 2**-53
. So we need to show that(1 - 2**-53) * n < n
for our positive integern
, since it'll always be true thatrandom() * n <= (1 - 2**-53) * n
.Proof (Sketch) Let
k
be the unique integerk
such that2**(k-1) < n <= 2**k
. Then the next float down fromn
isn - 2**(k-53)
. We need to show thatn*(1-2**53)
(i.e., the actual, unrounded, value of the product) is closer ton - 2**(k-53)
than ton
, so that it'll always be rounded down. But a little arithmetic shows that the distance fromn*(1-2**-53)
ton
is2**-53 * n
, while the distance fromn*(1-2**-53)
ton - 2**(k-53)
is(2**k - n) * 2**-53
. But2**k - n < n
(because we chosek
so that2**(k-1) < n
), so the product is closer ton - 2**(k-53)
, so it will get rounded down (assuming, that is, that the platform is doing some form of round-to-nearest).So we're safe. Phew!
Addendum (2015-07-04): The above assumes IEEE 754 binary64 arithmetic, with round-ties-to-even rounding mode. On many machines, that assumption is fairly safe. However, on x86 machines that use the x87 FPU for floating-point (for example, various flavours of 32-bit Linux), there's a possibility of double rounding in the multiplication, and that makes it possible for
random() * n
to round up ton
in the case whererandom()
returns the largest possible value. The smallest suchn
for which this can happen isn = 2049
. See the discussion at http://bugs.python.org/issue24546 for more.来自 Python 文档:
就像几乎所有浮点数的 PRNG 一样。
From Python documentation:
Like almost every PRNG of float numbers..