uniform(0, 1)
pode produzir 0
, mas nunca produzirá 1
.
A documentação informa que o terminal b
pode ser incluído nos valores produzidos:
O valor do ponto final b
pode ou não ser incluído no intervalo, dependendo do arredondamento do ponto flutuante na equação a + (b-a) * random()
.
Portanto uniform(0, 1)
, a fórmula 0 + (1-0) * random()
, simplificada para 1 * random()
, teria que ser capaz de produzir 1
exatamente. Isso só aconteceria se random.random()
fosse 1.0 exactly. However,
random () *never* produces
1.0`.
Citando a random.random()
documentação :
Retorne o próximo número de ponto flutuante aleatório no intervalo [0,0, 1,0).
A notação [..., ...)
significa que o primeiro valor faz parte de todos os valores possíveis, mas o segundo não. random.random()
vontade na maioria dos valores produzem muito perto de 1.0
. O float
tipo de Python é um valor de ponto flutuante IEEE 754 base64 , que codifica várias frações binárias (1/2, 1/4, 1/5 etc.) que compõem o valor, e o valor random.random()
produzido é simplesmente a soma de uma seleção aleatória dessas 53 frações de 2 ** -1
(1/2) a 2 ** -53
(1/9007199254740992).
No entanto, como ele pode produzir valores muito próximos 1.0
, juntamente com os erros de arredondamento que ocorrem quando você multiplica os nubmers de ponto flutuante, é possível produzir b
para alguns valores de a
e b
. Mas 0
e 1
não estão entre esses valores.
Observe que random.random()
pode produzir 0,0, portanto, a
é sempre incluído nos valores possíveis para random.uniform()
( a + (b - a) * 0 == a
). Como existem 2 ** 53
valores diferentes que random.random()
podem produzir (todas as combinações possíveis dessas 53 frações binárias), existe apenas uma 2 ** 53
chance de 1 em (então 1 em 9007199254740992) de que isso aconteça.
Portanto, o maior valor possível que random.random()
pode produzir é 1 - (2 ** -53)
; basta escolher um valor pequeno o suficiente para b - a
permitir o arredondamento quando multiplicado por random.random()
valores mais altos. Quanto menor b - a
, maiores as chances de isso acontecer:
>>> import random, sys
>>> def find_b():
... a, b = 0, sys.float_info.epsilon
... while random.uniform(a, b) != b:
... b /= 2
... else:
... return b
...
>>> print("uniform(0, {0}) == {0}".format(find_b()))
...
uniform(0, 4e-323) == 4e-323
Se você acertar b = 0.0
, dividimos 1023 vezes, o valor acima significa que tivemos sorte após 1019 divisões. O valor mais alto que encontrei até agora (executando a função acima em um loop com max()
) é 8.095e-320
(1008 divisões), mas provavelmente existem valores mais altos. É tudo um jogo de azar. :-)
Também pode acontecer se não houver muitas etapas discretas entre a
e b
, como quando a
e b
tiver um expoente alto e, portanto, parecer distante. Os valores de ponto flutuante ainda são apenas aproximações e o número de valores que eles podem codificar é finito. Por exemplo, há apenas 1 fração binária de diferença entre sys.float_info.max
e sys.float_info.max - (2 ** 970)
, portanto, há uma chance de 50-50 random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)
produz sys.float_info.max
:
>>> a, b = sys.float_info.max - (2 ** 970), sys.float_info.max
>>> values = [random.uniform(a, b) for _ in range(10000)]
>>> values.count(sys.float_info.max) # should be roughly 5000
4997
X ~ U(0,1)
, então,P(X=x)
é quase certamente 0, para todos os valores de x. (Isso ocorre porque existem infinitos valores possíveis no intervalo.) Se você está procurando exatamente 0 ou 1, deve usar uma função diferente - por exemplorandom.choice