2011-09-11 12 views
5

¿Por qué si uso un generador de números aleatorios y un rango de 0 a 9 no obtengo la misma distribución uniforme que la combinación con la función de piso?Números aleatorios y función de piso contra redondo

+5

se puede añadir código de ejemplo? (y para obtener crédito adicional, algunos datos estadísticos que comparan ambos y demuestran el problema) –

Respuesta

24

Math.floor(Math.random() * 10) ofrece una distribución bastante uniforme, mientras que Math.round(Math.random() * 10) no.

Math.floor() devuelve 0 para cualquier valor en el intervalo [0, 1) (1 exclusiva), 1 para cualquier valor en el intervalo [1, 2), etc.

Así que si tenemos Igual posibilidad de obtener un número en uno de estos rangos, obtendremos una distribución igual de 0 y 1.

Math.round(), sin embargo, devuelve 0 para valores por debajo de 0,5, 1 para valores por debajo de 1,5, etc.

así que en realidad tienen la mitad de las posibilidades de conseguir un 0, como valores sólo de 0 a 0,5 redondeará a 0.

╔═════════╦═════════╦═════════╗ 
║ Range ║ floor() ║ round() ║ 
╠═════════╬═════════╬═════════╣ 
║ [0, 1) ║ 0  ║ 0 or 1 ║ 
║ [1, 2) ║ 1  ║ 1 or 2 ║ 
║ [2, 3) ║ 2  ║ 2 or 3 ║ 
║ ...  ║ ...  ║ ...  ║ 
║ [9, 10) ║ 9  ║ 9 or 10 ║ 
╚═════════╩═════════╩═════════╝ 
+1

sí, eso es lo que estoy haciendo en este momento. Pero estoy preguntando ** por qué ** sin piso esta distribución no es tan uniforme como con piso. – user336635

+0

@ user336635: http://jsfiddle.net/pimvdb/fPJ6Q/ Bastante uniforme ... – pimvdb

+3

Imagina una línea en papel cuadriculado, 10 cuadrados de largo. 0 a la izquierda, 10 a la derecha, 5 a la derecha en el medio. Si usa round(), entonces la región medio cuadrado a la izquierda de 5, * y * medio cuadrado a la derecha de 5, se mapeará a 5. Sin embargo, solo la mitad de un cuadrado a la derecha de 0 se mapea a 0, no hay medio cuadrado a la izquierda de 0 en la línea. Cuando use floor(), solo los valores de un cuadrado a la derecha de n se asignarán a n, usted reducirá el número de resultados posibles, ya que no puede obtener 10 más. Sin embargo, cada uno de los 10 posibles resultados (0-9 inc) tiene el mismo "porcentaje" de la línea, y por lo tanto las mismas probabilidades de ocurrir. – Sophistifunk

2

me gusta mucho para desencadenar int de 31 bits en lugar de Math.floor(), haciendo un binario "0 o" la operación. Lo hace un poco más rápido (stack vs heap,) parece un poco más limpio, y hace lo mismo, en un sentido práctico. Aquí hay un ejemplo que pone un elemento aleatorio de una matriz:

var ar=[1,2,3,4,5,6,7,8,9,0,'a','b','c','d'] 
console.log(ar[(Math.random() * ar.length) |0]) 

Esto podría parecer como la optimización prematura, pero como dije, me gusta cómo se ve y se tarda menos tipificación de Math.floor(). Usando Math.round() requeriría un paso adicional (debido a la propagación es 1-ar.length no 0-ar.length-1)

+0

¿Cómo sabes que es un poco más rápido y, perdón por mi ignorancia, qué es pila vs. montón? Sé que tienen algo que ver con los algoritmos de clasificación – Anthony

+1

https://jsperf.com/random-array-item muestra que es un poco más rápido en mi navegador (en promedio, aproximadamente ± 0.5% - x ± 0.8% en Mac Chrome Versión 58.0 .3029.110 (64-bit)) aquí hay más información sobre stack/heap: http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap the '| 0' lo fuerza en int32 (lo redondea y lo escribe) para que pueda sentarse en la pila, mientras que los Números generales siempre están en el montón (en caso de que terminen siendo más grandes o tengan un punto decimal) – konsumer

+0

No hay una gran diferencia en la velocidad, pero es pequeño, y como dije, creo que se ve bien, también. – konsumer