uniform(0, 1)
puede producir 0
, pero nunca producirá 1
.
La documentación le dice que el punto final b
podría incluirse en los valores producidos:
El valor del punto final b
puede o no estar incluido en el rango dependiendo del redondeo de punto flotante en la ecuación a + (b-a) * random()
.
Entonces uniform(0, 1)
, para , la fórmula 0 + (1-0) * random()
, simplificada a 1 * random()
, tendría que ser capaz de producir 1
exactamente. Eso solo sucedería si random.random()
es 1.0 exactly. However,
random () *never* produces
1.0`.
Citando la random.random()
documentación :
Devuelve el siguiente número aleatorio de coma flotante en el rango [0.0, 1.0).
La notación [..., ...)
significa que el primer valor es parte de todos los valores posibles, pero el segundo no lo es. random.random()
como máximo producirá valores muy cercanos a 1.0
. El float
tipo de Python es un valor de coma flotante base64 IEEE 754 , que codifica varias fracciones binarias (1/2, 1/4, 1/5, etc.) que conforman el valor, y el valor que random.random()
produce es simplemente la suma de un selección aleatoria de esas 53 fracciones de este tipo 2 ** -1
( desde 1/2) hasta 2 ** -53
(1/9007199254740992).
Sin embargo, debido a que puede producir valores muy cerca 1.0
, junto con los errores de redondeo que se producen cuando se multiplican flotante nubmers de puntos, se puede producir b
para algunos valores de a
y b
. Pero 0
y 1
no están entre esos valores.
Tenga en cuenta que random.random()
puede producir 0.0, por a
lo que siempre se incluye en los valores posibles para random.uniform()
( a + (b - a) * 0 == a
). Debido a que existen 2 ** 53
diferentes valores que random.random()
pueden producir (todas las combinaciones posibles de esas 53 fracciones binarias), solo hay una 2 ** 53
posibilidad de 1 pulg.
Entonces el valor más alto posible que random.random()
puede producir es 1 - (2 ** -53)
; simplemente elija un valor lo suficientemente pequeño como para b - a
permitir que se redondee cuando se multiplica por random.random()
valores más altos. Cuanto más pequeño b - a
es, mayores son las posibilidades de que eso suceda:
>>> 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
Si aciertas b = 0.0
, entonces hemos dividido 1023 veces, el valor anterior significa que tuvimos suerte después de 1019 divisiones. El valor más alto que encontré hasta ahora (ejecutando la función anterior en un bucle con max()
) es 8.095e-320
(1008 divisiones), pero probablemente haya valores más altos. Todo es un juego de azar. :-)
También puede suceder si no hay muchos pasos discretos entre a
y b
, como cuando a
y b
tienen un alto exponente y, por lo tanto, puede parecer muy diferente. Los valores de coma flotante siguen siendo solo aproximaciones, y el número de valores que pueden codificar es finito. Por ejemplo, solo hay 1 fracción binaria de diferencia entre sys.float_info.max
y sys.float_info.max - (2 ** 970)
, por lo que hay una probabilidad de 50-50 que random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)
produce 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)
, entoncesP(X=x)
es casi seguro 0, para todos los valores de x. (Esto se debe a que hay infinitos valores posibles en el intervalo). Si está buscando exactamente 0 o 1, debe usar una función diferente, por ejemplorandom.choice