Hay dos formas obvias de generar un dígito aleatorio del 0 al 9 en Python. Se podría generar un número aleatorio de coma flotante entre 0 y 1, multiplicar por 10 y redondear hacia abajo. Alternativamente, se podría usar el método random.randint .
import random def random_digit_1(): return int(10 * random.random()) def random_digit_2(): return random.randint(0, 9)Tenía curiosidad sobre qué pasaría si uno generara un número aleatorio entre 0 y 1 y mantuviera el último dígito. No esperaba necesariamente que la distribución fuera uniforme, pero encontré el resultado bastante sorprendente.
from random import random, seed from collections import Counter seed(0) counts = Counter(int(str(random())[-1]) for _ in range(1_000_000)) print(counts)Producción:
Counter({1: 84206, 5: 130245, 3: 119433, 6: 129835, 8: 101488, 2: 100861, 9: 84796, 4: 129088, 7: 120048})A continuación se muestra un histograma. Tenga en cuenta que 0 no aparece, ya que los ceros finales se truncan. Pero, ¿alguien puede explicar por qué los dígitos 4, 5 y 6 son más comunes que el resto? Usé Python 3.6.10, pero los resultados fueron similares en Python 3.8.0a4.
Ese no es "el último dígito" del número. Ese es el último dígito de la cadena que str te dio cuando pasó el número.
Cuando llamas a str en un flotante, Python te da suficientes dígitos para que llamar a float en la cadena te dé el flotante original. Para este propósito, es menos probable que sea necesario un 1 o 9 final que otros dígitos, porque un 1 o 9 final significa que el número está muy cerca del valor que obtendría al redondear ese dígito. Es muy probable que no haya otros flotantes más cerca y, de ser así, ese dígito se puede descartar sin sacrificar el comportamiento de float(str(original_float)) .
Si str le diera suficientes dígitos para representar exactamente el argumento, el último dígito casi siempre sería 5, excepto cuando random.random() devuelve 0.0, en cuyo caso el último dígito sería 0. (Los flotantes solo pueden representar racionales diádicos , y el último dígito decimal distinto de cero de un racional diádico no entero es siempre 5.) Las salidas también serían extremadamente largas, pareciendo
>>> import decimal, random >>> print(decimal.Decimal(random.random())) 0.29711195452007921335990658917580731213092803955078125 que es una de las razones por las que str no hace eso.
Si str le diera exactamente 17 dígitos significativos (suficientes para distinguir todos los valores flotantes entre sí, pero a veces más dígitos de los necesarios), entonces el efecto que está viendo desaparecería. Habría una distribución casi uniforme de los dígitos finales (incluido el 0).
(Además, olvidó que str a veces devuelve una cadena en notación científica, pero ese es un efecto menor, porque hay una baja probabilidad de obtener un flotante donde eso sucedería de random.random() .