En la documentación se dice que existe la posibilidad de que { {X0}} puede generar los valores 0 y 1.

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

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

9
Venkatesh Gandi 4 oct. 2019 a las 21:58

4 respuestas

La mejor respuesta

uniform(0, 1) puede producir 0, pero nunca producirá 1.

La documentación le dice que el punto final b < em> podría incluirse en los valores producidos:

El valor de punto final b puede o no ser incluido en el rango dependiendo del redondeo de punto flotante en la ecuación a + (b-a) * random().

Entonces, para uniform(0, 1), 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. random.random() como máximo producirá 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 que produce random.random() es simplemente la suma de una selección aleatoria de esas 53 fracciones de este tipo 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) sucediendo.

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 el redondeo cuando se multiplique por valores más altos random.random(). Cuanto menor sea b - a, mayores serán 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 presiona 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 de probabilidad de que random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max) produzca 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
13
Martijn Pieters 6 oct. 2019 a las 14:31

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 muestrean 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 aprovecha 10 cuatrillones de muestras para encontrar un 0. Por supuesto, puede encontrarlo en sus primeros 10 intentos, o nunca .

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

1
Celius Stingher 4 oct. 2019 a las 19:13

"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 valores aleatorios cuatrillones antes de obtener un valor que sea exactamente 0 o 1. Por lo tanto, es posible, pero es muy probable que nunca lo observe.

5
hobbs 4 oct. 2019 a las 19:05

Por supuesto. Ya estabas en el camino correcto al intentar uniform(0, 0.001) en su 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
1
wim 4 oct. 2019 a las 19:24
58241868