python random uniform-distribution

python - ¿Puede random.uniform(0,1) generar 0 o 1?



uniform-distribution (4)

"Varias veces" no es suficiente. 10,000 no es suficiente. random.uniform elige entre 2 ^ 53 (9,007,199,254,740,992) valores diferentes. Estás interesado en dos de ellos. Como tal, debe esperar generar varios billones de valores aleatorios antes de obtener un valor que sea exactamente 0 o 1. Por lo tanto, es posible, pero es muy probable que nunca lo observe.

En la documentación se dice que existe la posibilidad de que uniform(0,1) pueda generar los valores 0 y 1 .

He corrido uniform(0, 1) 10000 veces, pero nunca produjo cero. Incluso en el caso del uniform(0, 0.001) .

¿Puede random.uniform(0,1) generar 0 o 1 ?


Puede intentar generar un bucle que cuente la cantidad de iteraciones necesarias para que se muestre un 0 exacto (no).

Además, como dijo Hobbs, la cantidad de valores que se muestrea de manera uniformly son 9,007,199,254,740,992. Lo que significa que la probabilidad de ver un 0 es exactamente 1 / 9,007,199,254,740,992. Lo que en términos generales y redondeando significa que necesitará en promedio 10 billones de muestras para encontrar un 0. Por supuesto, puede encontrarlo en sus primeros 10 intentos, o nunca.

El muestreo de un 1 es imposible ya que el intervalo definido para los valores se cierra con un paréntesis, por lo tanto, no incluye 1.


Seguro. Ya estabas en el camino correcto con probar uniform(0, 0.001) lugar. Solo sigue restringiendo los límites lo suficiente como para que suceda antes.

>>> random.uniform(0., 5e-324) 5e-324 >>> random.uniform(0., 5e-324) 5e-324 >>> random.uniform(0., 5e-324) 0.0


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 de punto final b puede o no incluirse en el rango dependiendo del redondeo de punto flotante en la ecuación a + (ba) * random() .

Entonces, para el uniform(0, 1) , la fórmula 0 + (1-0) * random() , simplificada a 1 * random() , debería ser capaz de producir 1 exactamente. Eso solo sucedería si random.random() es 1.0 exactly. However, exactly. However, random () *never* produces 1.0`.

Citando la documentación random.random() :

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. random.random() producirá como máximo valores muy cercanos a 1.0 . El tipo float 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 random.random() produce es simplemente la suma de una selección aleatoria de esas 53 fracciones, desde 2 ** -1 (1/2) hasta 2 ** -53 (1/9007199254740992).

Sin embargo, debido a que puede producir valores muy cercanos a 1.0 , junto con los errores de redondeo que ocurren cuando multiplica los nubmers de punto flotante, 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 lo que a siempre se incluye en los valores posibles para random.uniform() ( a + (b - a) * 0 == a ). Debido a que hay 2 ** 53 valores diferentes que random.random() puede producir (todas las combinaciones posibles de esas 53 fracciones binarias), solo existe una probabilidad de 1 en 2 ** 53 (por lo tanto, 1 en 9007199254740992) de que eso ocurra.

Entonces, el valor más alto posible que random.random() puede producir es 1 - (2 ** -53) ; simplemente elija un valor lo suficientemente pequeño para b - a para permitir que el redondeo se random.random() cuando se multiplica por valores random.random() más altos. Cuanto más pequeño es b - a , 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 tocas 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 (ejecutar 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 un 50-50 chance 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