是否可以在完全开放的区间或高端封闭的区间内在python中生成随机数? [英] Is it possible to generate a random number in python on a completely open interval or one that is closed on the high end?

查看:37
本文介绍了是否可以在完全开放的区间或高端封闭的区间内在python中生成随机数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想生成一个随机数 n 使得 n 在范围 (a,b)(a,b] where a .这在 python 中可能吗?似乎唯一的选择是 a + random.random()*(ba) 包括 [a,b)random.uniform(a,b) 包括范围 [a,b] 所以两者都不是满足我的需求.

解决方案

随机"数字的计算机生成很棘手,尤其是随机"浮点数.你需要深思熟虑很难知道你真正想要什么.最后,您需要在整数之上构建一些东西,而不是直接从浮点数中构建.

在幕后,在 Python(以及使用 Mersenne Twister 源代码的所有其他语言)中,生成随机"IEEE-754 双精度值(Python 的基本 random.random())确实有效生成一个随机的 53 位整数,然后除以 2**53:

randrange(2**53)/9007199254740992.0

这就是输出范围是 [0.0, 1.0) 的原因,但并非该范围内所有可表示的浮点数都具有相同的可能性.只有那些可以以 I/2**53 形式表示的整数 0 <= I 2**53.例如,永远无法返回浮点数 1.0/2**60.

这里没有实数",只有可表示的二进制浮点数,因此要回答您的问题首先需要您指定要从中选择的确切数字集.

如果答案是你不想那么挑剔,那么开放和封闭之间的区别也太挑剔了.如果您可以指定精确集合,那么解决方案是生成映射到输出集的或多或少明显的随机整数.

例如,如果您想从 [3.0, 6.0] 中选择小数点后仅 2 位的随机"浮点数,则有 13 种可能的输出.所以第一步是

i = random.randrange(13)

然后映射到感兴趣的范围:

返回 3.0 + i/4.0

无用但有教育意义;-)

正如评论中所指出的,从所有可表示的浮点数 x 中统一挑选 0.0 <×<1.0 可以实现,但距离在该范围内均匀分布还很远.例如,[0.5, 1.0) 中有 2**52 可表示的浮点数,2**52 也有 2**52 可表示的浮点数.code>[0.25, 0.5), and ... in [2.0**-i, 2.0**(1-i)) 用于增加 i直到当我们达到次正常范围时可表示的浮点数开始减少,当我们完全下溢到 0 时最终下降到零.

作为位模式,它们非常简单:当查看位时,(0, 1) 中的一组可表示的 IEEE-754 doubles(Python 在几乎所有平台上浮动)包括模式作为整数,简单地

range(1, 0x3ff0000000000000)

因此,使用比特摆弄技巧可以很容易地编写一个生成具有相同可能性的函数:

from struct import 解压从随机导入随机数定义 gen01():i = randrange(1, 0x3ff0000000000000)as_bytes = i.to_bytes(8, "big")return unpack(">d", as_bytes)[0]

只需运行几次,看看为什么它没有用 - 它非常严重地偏向范围的 0.0 端:

<预><代码>>>>对于范围内的我(10):...打印(gen01())9.796357610869274e-1044.125848254595866e-1971.8114434720880952e-2531.4937625148849258e-2851.0537573744489343e-3042.79008159472542e-584.718459887295062e-2172.7996009087703915e-2953.4129442284798105e-1702.299402306630583e-115

I would like to generate a random number n such that n is in the range (a,b) or (a,b] where a < b. Is this possible in python? It seems the only choices are a + random.random()*(b-a) which is includes [a,b) or random.uniform(a,b) which includes the range [a,b] so neither meet my needs.

解决方案

Computer generation of "random" numbers is tricky, and especially of "random" floats. You need to think long & hard about what you really want. In the end, you'll need to build something on top of integers, not directly out of floats.

Under the covers, in Python (and every other language using the Mersenne Twister's source code), generating a "random" IEEE-754 double (Python's basic random.random()) really works by generating a random 53-bit integer, then dividing by 2**53:

randrange(2**53) / 9007199254740992.0

That's why the output range is [0.0, 1.0), but not all representable floats in that range are equally likely. Only the ones that can be expressed in the form I/2**53 for an integer 0 <= I < 2**53. For example, the float 1.0 / 2**60 can never be returned.

There are no "real numbers" here, just representable binary-floating-point numbers, so to answer your question first requires that you specify the exact set of those from which you're trying to pick.

If the answer is that you don't want to get that picky, then the distinction between open and closed is also too picky to bother with. If you can specify the precise set, then the solution is to generate more-or-less obvious random integers that map to your output set.

For example, if you want to pick "random" floats from [3.0, 6.0] with just 2 bits after the radix point, there are 13 possible outputs. So the first step is

i = random.randrange(13)

Then map to the range of interest:

return 3.0 + i / 4.0

EDIT: USELESS BUT EDUCATIONAL ;-)

As noted in the comments, picking uniformly from all representable floats x with 0.0 < x < 1.0 can be done, but is very far from being uniformly distributed across that range. There are, for example, 2**52 representable floats in [0.5, 1.0), but also 2**52 representable floats in [0.25, 0.5), and ... in [2.0**-i, 2.0**(1-i)) for increasing i until the number of representable floats starts shrinking when we hit the subnormal range, eventually falling to none when we underflow to 0 completely.

As bit patterns they're very simple, though: the set of representable IEEE-754 doubles (Python floats on almost all platforms) in (0, 1) consists of, when viewing the bit patterns as integers, simply

range(1, 0x3ff0000000000000)

So a function to generate each of those with equal likelihood is straightforward to write using bit-fiddling tricks:

from struct import unpack
from random import randrange

def gen01():
    i = randrange(1, 0x3ff0000000000000)
    as_bytes = i.to_bytes(8, "big")
    return unpack(">d", as_bytes)[0]

Just run that a few times to see why it's useless - it's very heavily skewed toward the 0.0 end of the range:

>>> for i in range(10):
...     print(gen01())

9.796357610869274e-104
4.125848254595866e-197
1.8114434720880952e-253
1.4937625148849258e-285
1.0537573744489343e-304
2.79008159472542e-58
4.718459887295062e-217
2.7996009087703915e-295
3.4129442284798105e-170
2.299402306630583e-115

这篇关于是否可以在完全开放的区间或高端封闭的区间内在python中生成随机数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆