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 bpode 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 1exatamente. Isso só aconteceria se random.random()fosse 1.0 exactly. However,random () *never* produces1.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 floattipo 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 bpara alguns valores de ae b. Mas 0e 1nã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 ** 53valores diferentes que random.random()podem produzir (todas as combinações possíveis dessas 53 frações binárias), existe apenas uma 2 ** 53chance 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 - apermitir 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 ae b, como quando ae btiver 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.maxe 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