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

发布于 2024-09-05 13:40:56 字数 629 浏览 5 评论 0 原文

在研究这个问题并阅读random.py中的源代码时,我开始想知道是否randrangerandint 确实表现得像“广告”。我非常倾向于相信这一点,但按照我的理解,randrange 本质上是实现为

start + int(random.random()*(stop-start))

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

randint(start, stop) 正在调用 randrange(start, stop+ 1),从而返回 1 到 10 之间的数字。

我现在的问题是:

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

When researching for this question and reading the sourcecode in random.py, I started wondering whether randrange and randint really behave as "advertised". I am very much inclined to believe so, but the way I read it, randrange is essentially implemented as

start + int(random.random()*(stop-start))

(assuming integer values for start and stop), so randrange(1, 10) should return a random number between 1 and 9.

randint(start, stop) is calling randrange(start, stop+1), thereby returning a number between 1 and 10.

My question is now:

If random() were ever to return 1.0, then randint(1,10) would return 11, wouldn't it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陌上青苔 2024-09-12 13:40:56

来自 random.py 和文档:

"""Get the next random number in the range [0.0, 1.0)."""

) 表示间隔不包含 1.0。也就是说,它永远不会返回1.0。

这是数学中的一般约定,[] 包含在内,而 () 排除,并且两种类型的括号可以混合使用,如 (a, b][a, b)。查看维基百科:间隔(数学)以获得正式解释。

From random.py and the docs:

"""Get the next random number in the range [0.0, 1.0)."""

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.

沧桑㈠ 2024-09-12 13:40:56

其他答案指出,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* 的 n 使用 int(random() * n) 方法*53(这里和下面我假设该平台使用 IEEE 754 双精度),这是 n 转换为浮点数保证不会丢失信息的范围(因为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**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 - 2**(k-53),因此它向下舍入(假设平台正在进行某种形式的舍入-最近的)。

所以我们很安全。唷!


附录 (2015-07-04):上面假设 IEEE 754 二进制 64 算法,采用舍入到偶数舍入模式。在许多机器上,这种假设是相当安全的。但是,在使用 x87 FPU 进行浮点运算的 x86 计算机上(例如,各种版本的 32 位 Linux),可能会出现 乘法中的双舍入,这使得 random() * n 可以向上舍入到 nrandom() 返回最大可能值的情况下。可能发生这种情况的最小 nn = 2049。有关更多信息,请参阅 http://bugs.python.org/issue24546 上的讨论。

Other answers have pointed out that the result of random() is always strictly less than 1.0; however, that's only half the story.

If you're computing randrange(n) as int(random() * n), you also need to know that for any Python float x satisfying 0.0 <= x < 1.0, and any positive integer n, it's true that 0.0 <= x * n < n, so that int(x * n) is strictly less than n.

There are two things that could go wrong here: first, when we compute x * n, n is implicitly converted to a float. For large enough n, that conversion might alter the value. But if you look at the Python source, you'll see that it only uses the int(random() * n) method for n smaller than 2**53 (here and below I'm assuming that the platform uses IEEE 754 doubles), which is the range where the conversion of n to a float is guaranteed not to lose information (because n 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. If x is close enough to 1.0, it's conceivable that the rounding will round the result up to n 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 integer n, since it'll always be true that random() * n <= (1 - 2**-53) * n.

Proof (Sketch) Let k be the unique integer k such that 2**(k-1) < n <= 2**k. Then the next float down from n is n - 2**(k-53). We need to show that n*(1-2**53) (i.e., the actual, unrounded, value of the product) is closer to n - 2**(k-53) than to n, so that it'll always be rounded down. But a little arithmetic shows that the distance from n*(1-2**-53) to n is 2**-53 * n, while the distance from n*(1-2**-53) to n - 2**(k-53) is (2**k - n) * 2**-53. But 2**k - n < n (because we chose k so that 2**(k-1) < n), so the product is closer to n - 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 to n in the case where random() returns the largest possible value. The smallest such n for which this can happen is n = 2049. See the discussion at http://bugs.python.org/issue24546 for more.

只等公子 2024-09-12 13:40:56

来自 Python 文档:

几乎所有模块函数都依赖于基本函数 random(),它均匀地生成半开范围 [0.0, 1.0) 内的随机浮点数。

就像几乎所有浮点数的 PRNG 一样。

From Python documentation:

Almost all module functions depend on the basic function random(), which generates a random float uniformly in the semi-open range [0.0, 1.0).

Like almost every PRNG of float numbers..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文