2011-10-08 13 views
6

Domanda: Supponiamo di avere un generatore di numeri casuali randn() che restituisce un numero casuale distribuito uniformemente tra 0 e n-1. Dato un numero qualsiasi m, scrivi un generatore di numeri casuali che restituisca un numero casuale distribuito uniformemente tra 0 e m-1.Come ottenere numeri casuali con il generatore errato

La mia risposta:

-(int)randm() { 
    int k=1; 
    while (k*n < m) { 
     ++k; 
    } 
    int x = 0; 
    for (int i=0; i<k; ++i) { 
     x += randn(); 
    } 
    if (x < m) { 
     return x; 
    } else { 
     return randm(); 
    } 
} 

È corretto?

+1

Avete ulteriori informazioni su 'n' e' m'? – PengOne

+0

Parte della domanda era cosa dovevo dare per n e m per far funzionare questo, ma penso che funzioni per qualsiasi numero. – WisaF

+1

Stai assumendo una serie di cose su n, m: 1) entrambi sono numeri interi, 2) entrambi sono positivi – RHSeeger

risposta

9

Sei vicino, ma il problema con la tua risposta è che c'è più di un modo per scrivere un numero come somma di altri due numeri.

Se m<n, questo funziona perché i numeri 0,1,...,m-1 appaiono ciascuno con uguale probabilità e l'algoritmo termina quasi sicuramente.

Questa risposta non funziona in generale perché esiste più di un modo per scrivere un numero come somma di altri due numeri. Ad esempio, c'è solo un modo per ottenere 0 ma ci sono molti modi per ottenere m/2, quindi le probabilità non saranno uguali.

Esempio: n = 2 e m=3

0 = 0+0 
1 = 1+0 or 0+1 
2 = 1+1 

così la distribuzione di probabilità dal tuo metodo è

P(0)=1/4 
P(1)=1/2 
P(2)=1/4 

che non è uniforme.


Per risolvere questo problema, è possibile utilizzare una fattorizzazione unica. Scrivi m nella base n, tenendo traccia del più grande esponente necessario, ad esempio e. Quindi, trova il multiplo più grande di m più piccolo di n^e, chiamalo k. Infine, genera i numeri e con randn(), prendili come espansione n di base del numero x, se x < k*m, restituisci x, altrimenti riprova.

Supponendo che m < n^2, quindi

int randm() { 

    // find largest power of n needed to write m in base n 
    int e=0; 
    while (m > n^e) { 
     ++e; 
    } 

    // find largest multiple of m less than n^e 
    int k=1; 
    while (k*m < n^2) { 
     ++k 
    } 
    --k; // we went one too far 

    while (1) { 
     // generate a random number in base n 
     int x = 0; 
     for (int i=0; i<e; ++i) { 
      x = x*n + randn(); 
     } 
     // if x isn't too large, return it x modulo m 
     if (x < m*k) 
      return (x % m); 
    } 
} 
4

non è corretto.

Si aggiungono numeri casuali uniformi, che non producono un risultato casuale uniforme. Dire n = 2 e m = 3, quindi i valori possibili per x sono 0 + 0, 0 + 1, 1 + 0, 1 + 1. Quindi hai il doppio delle probabilità di ottenere 1 di quello che ottieni 0 o 2.

Quello che devi fare è scrivere m in base n, e quindi generare 'cifre' della rappresentazione base-n del casuale numero. Quando hai il numero completo, devi controllare se è inferiore a m. Se lo è, allora hai finito. Se non lo è, allora è necessario ricominciare da capo.

3

La somma di due generatori di numeri casuali uniformi non viene generata in modo uniforme. Ad esempio, la somma di due dadi è più probabile che sia 7 su 12, perché per ottenere 12 devi lanciare due sei, mentre puoi ottenere 7 come 1 + 6 o 6 + 1 o 2 + 5 o 5 + 2 o ...

Supponendo che randn() restituisce un intero compreso tra 0 e n - 1, n * randn() + randn() è distribuito uniformemente tra 0 e n * n - 1, in modo da poter aumentare la sua gamma. Se randn() restituisce un numero intero compreso tra 0 e k * m + j - 1, quindi chiamalo ripetutamente finché non ottieni un numero < = k * m - 1, quindi dividi il risultato per k per ottenere un numero uniformemente distribuito tra 0 e m -1.

+0

+1 per l'esempio dei dadi. –

0

Supponendo che entrambi n sono meri interi positivi, l'algoritmo standard del ridimensionamento non dovrebbe funzionare?

return (int)((float)randn() * m/n); 
+3

La distribuzione non è uniforme a meno che n non sia un multiplo esatto di m. Se m> n, alcuni valori mancheranno. (Prova m = 3, n = 2: otterrai sempre 0 e 1, mai 2). Se m

+0

Ah, ok, questo ha senso. Non ci avevo pensato. Grazie. Lascerò qui la mia risposta piuttosto che cancellarla, dal momento che il tuo commento è un'ottima spiegazione del perché non funzionerà. – RHSeeger

Problemi correlati