2015-10-16 34 views
11

data una funzione Math.random() che restituisce un numero compreso tra [0,1) e minmax valori per specificare l'intervallo, come è possibile generare numeri per seguenti casi:Genera numeri casuali nell'intervallo specificato - vari casi (int, float, inclusivo, esclusivo)

caso vogliamo intero:

  • A: (min,max) ?
  • B: [min,max) return Math.floor(Math.random() * (max - min)) + min;
  • C: (min,max] ?
  • D: [min,max] return Math.floor(Math.random() * (max - min + 1)) + min;

caso vogliamo float:

  • A: (min,max) ?
  • B: [min,max) return Math.random() * (max - min) + min;
  • C: (min,max] ?
  • D: [min,max] ?
+0

il mio riferimento proviene da [MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) – tgogos

+0

I sta corretti –

+0

Il 'float B' caso non funziona: in molti casi, quella formula sarà in grado di generare il limite superiore e il limite inferiore. –

risposta

0

intero:

  • A: return Math.floor(Math.random() * (max - min - 1)) + min + 1;
  • B Corretto
  • C: Questa è la stessa [min + 1, max + 1), quindi: return Math.floor(Math.random() * (max - min)) + min + 1;
  • D: corretto

Per i galleggianti, è necessario sapere quale tipo di aritmetica in virgola mobile è disponibile. A meno che non si usi una libreria speciale, l'uguaglianza in float è qualcosa che di solito non accade, quindi non ha senso avere intervalli chiusi. Come tale non ci dovrebbe essere alcuna differenza tra tutti e quattro e si può solo andare con:

return Math.random() * (max-min) + min;

Per la domanda di senso, è necessario definire un intervallo minimo accettabile per l'uguaglianza (ad esempio r=0.00000000000000001). Successivamente è possibile trasformare le equazioni a intervallo aperto (ad esempio (min, max)) in [min+r, max-r].

2

interi tua formula per B. è corretta, tutto il resto è ottenuto da banali +1-1 correzioni:

  • A. (min, max) = [min + 1, max), pertanto, da B. otteniamo min + 1 + Math.floor(Math.random() * (max - min - 1))
  • B. min + Math.floor(Math.random() * (max - min))
  • C. Poiché nell'intervallo aritmetico (min, max] = max - [0, max - min), si potrebbe anche scrivere max - Math.floor(Math.random() * (max - min))
  • D.[min, max] = [min, max + 1), quindi: min + Math.floor(Math.random() * (max + 1 - min))

Galleggianti. Come già sottolineato V13, la domanda è in qualche modo mal posta: se consideriamo i singoli punti come set zero-misura, c'è quasi (in senso teorico-di misura) nessuna differenza tra i quattro set ... Tuttavia, se vuoi per garantire che i confini di intervallo esclusi sono mai (non semplicemente "quasi mai") ​​campionati, e se si assume che non ci siano errori di arrotondamento, si potrebbe fare qualcosa di simile:

  • a: var middle = (min + max)/2; var sign = Math.random() > 0.5 ? 1 : -1; return middle + sign * (max - min)/2 * Math.random(); questa soluzione mette un po 'più grande massa su 0, ma questo dovrebbe essere trascurabile per tutti gli scopi pratici.

  • B: min + Math.random() * (max - min), sì.

  • C: max - Math.random() * (max - min), simmetrico a quanto sopra.
  • D: Non è possibile garantire di raggiungere mai il limite di intervallo superiore, quindi è sufficiente utilizzare min + Math.random() * (max - min).

La differenza tra A e D è il seguente: se si è cercato di utilizzare la formula min + Math.random() * (max - min) in A, potremmo occasionalmente ottenere un 0 (perché la gamma di possibili numeri è effettivamente finito). Tuttavia, nessuna statistica ragionevole potrebbe mai lamentarsi del fatto che il limite superiore non viene colpito in D.

0

Inizierò definendo le prossime due funzioni di supporto e quindi le useremo per ottenere i valori. Questi metodi sono le tue definizioni dei casi B.

int nextInt(int min, int max) { 
    return Math.floor(Math.random() * (max - min)) + min; 
} 

float nextFloat(float min, float max) { 
    return Math.random() * (max - min) + min; 
} 

Poi per interi

  • A: tornare nextInt (min + 1, max);
  • B: return nextInt (min, max);
  • C: return nextInt (min + 1, max + 1);
  • D: return nextInt (min, max + 1);

I galleggianti sono un caso un po 'più complesso. Qualcuno potrebbe obiettare che non c'è molta differenza se gli end point sono inclusi o meno - specialmente una soluzione aperta può essere usata al posto di chiusa - dal momento che i punti finali vengono selezionati raramente. Ma dal momento che è perfettamente possibile implementare tutti gli scenari, penso che ci sia un interesse matematico su come può essere fatto.

A: In questo caso semplice possiamo fare in modo che il valore di illegale è rotolato ancora:

float f; 
do { 
    f = nextFloat(min, max); 
} while (f == min); 
return f; 

B:

return nextFloat(min, max); 

C: Qui abbiamo appena passare the endpoint

float f = nextFloat(min, max); 
if (f == min) { 
    return max; 
} 
return f; 

D: Questo è il più complesso scenario di tutto, ma può essere realizzato come segue:

float f = nextFloat(min, max); 
if (f == min) { 
    return max; 
} 
return nextFloat(min, max); 

I casi A e D sono un po 'sporca nel senso che possono richiedere la generazione più numero casuale, che potrebbe essere un problema in alcuni scenari specifici. Risolvere ciò richiederebbe di scavare in profondità nelle specifiche del punto mobile per trovare implementazioni alternative. Inoltre si dovrebbe notare che nel caso D la propensione del valore massimo ha una propensione leggermente superiore rispetto a qualsiasi altro numero, se la funzione di riferimento è completamente uniforme (di solito non), ma di solito questa è solo una questione teorica. (Per essere precisi, se ci sono n valori possibili all'interno dell'intervallo, la propensione del valore massimo pmax = 1/(n-1) e la propabilità di qualsiasi altro valore è (1-pmax)/(n-1)).

Un piccolo problema che dovrebbe essere curato in implementazioni precise del caso A in virgola mobile, dovrebbe essere notato. Esiste la possibilità che il chiamante della funzione lo chiamerà con punti mobili adiacenti. Questo non è facile da vedere con un controllo fittizio dei parametri, quindi per essere sicuri ci dovrebbe essere un limite su quante volte il ciclo può essere eseguito.