2011-09-11 20 views
5

Perché se utilizzo il generatore di numeri casuali e l'intervallo 0 - 9 non ottengo la stessa distribuzione uniforme combinata con la funzione floor?Numeri casuali e funzione floor vs round

+5

si può aggiungere codice di esempio? (e per il credito extra, alcuni dati statistici che confrontano entrambi e dimostra il problema) –

risposta

24

Math.floor(Math.random() * 10) fornisce una distribuzione abbastanza uniforme, mentre Math.round(Math.random() * 10) no.

Math.floor() restituisce 0 per ogni valore nell'intervallo [0, 1) (1 esclusivo), 1 per ogni valore nell'intervallo [1, 2), ecc

Quindi, se abbiamo uguali possibilità di ottenere un numero in uno di questi intervalli, otterremo una uguale distribuzione di 0 e 1.

Math.round(), invece, restituisce 0 per i valori sotto 0.5, 1 per valori inferiori a 1,5, ecc

Quindi in realtà abbiamo la metà delle probabilità di ottenere un 0, come valori solo da 0 a 0,5 arrotonderà 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ì, è quello che sto facendo al momento. Ma sto chiedendo ** perché ** senza pavimento questa distribuzione non è così uniforme come con il pavimento. – user336635

+0

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

+3

Immagina una linea su carta millimetrata, lunga 10 quadrati. 0 a sinistra, 10 a destra, 5 a destra nel mezzo. Se usi round(), quindi la regione a mezzo quadrato a sinistra di 5, * e * a metà di un quadrato a destra di 5, verrà mappata a 5. Tuttavia, solo metà di un quadrato a destra di 0 esegue lo 0, non c'è mezzo a quadrato a sinistra di 0 sulla linea. Quando si usa floor(), solo i valori di un quadrato a destra di n verranno mappati e si riduce il numero di risultati possibili, in quanto non è possibile ottenere 10 di più. Tuttavia, ognuno dei 10 possibili risultati (0-9 inc) ha la stessa "condivisione" della linea, e quindi le stesse probabilità di occorrenza. – Sophistifunk

2

mi piace molto per far scattare 31 bit int invece di Math.floor(), facendo una "o 0" un'operazione binaria. Lo rende leggermente più veloce (stack vs heap,) sembra un tad più ordinato, e fa la stessa cosa, in senso pratico. Ecco un esempio che ottiene un elemento casuale di un array:

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

Questo potrebbe sembrare ottimizzazione prematura, ma come ho detto, mi piace come appare, e ci vuole meno di battitura di Math.floor(). Utilizzando Math.round() richiederebbe un passo in più (perché lo spread è 1-ar.length non 0-ar.length-1)

+0

Come sai che è leggermente più veloce e, scusa la mia ignoranza, che cos'è lo stack rispetto all'heap? So che hanno qualcosa a che fare con algoritmi di ordinamento – Anthony

+1

https://jsperf.com/random-array-item mostra che è leggermente più veloce sul mio browser (in media circa ± 0,5% - x ± 0,8% su Mac Chrome versione 58.0 .3029.110 (64-bit)) ecco di più sullo stack/heap: http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap il '| 0' lo forza in int32 (lo arrotonda e lo digita) in modo che possa sedersi nello stack, dove i numeri generali sono sempre nell'heap (nel caso in cui finiscano più grandi o abbiano un punto decimale.) – konsumer

+0

Non è un'enorme differenza di velocità, ma è piccolo, e come ho detto, penso che sia anche bello. – konsumer