2015-09-30 5 views
26

In base ai seguenti risultati, la generazione di numeri interi casuali uniformi tra due numeri utilizzando l'operazione % è quasi 3 volte più veloce rispetto all'utilizzo di std::uniform_int_distribution: Esistono buoni motivi per utilizzare std::uniform_int_distribution?Quali sono i vantaggi dell'utilizzo di uniform_int_distribution rispetto a un'operazione di modulo?

Codice:

#include <iostream> 
#include <functional> 
#include <vector> 
#include <algorithm> 
#include <random> 

#include <cstdio> 
#include <cstdlib> 

using namespace std; 

#define N 100000000 

int main() 
{ 

clock_t tic,toc; 

for(int trials=0; trials<3; trials++) 
{ 
    cout<<"trial: "<<trials<<endl; 

    // uniform_int_distribution 
    { 
     int res = 0; 
     mt19937 gen(1); 
     uniform_int_distribution<int> dist(0,999); 

     tic = clock(); 
     for(int i=0; i<N; i++) 
     { 
      int r = dist(gen); 
      res += r; 
      res %= 1000; 
     } 
     toc = clock(); 
     cout << "uniform_int_distribution: "<<(float)(toc-tic)/CLOCKS_PER_SEC << endl; 
     cout<<res<<" "<<endl; 

    } 

    // simple modulus operation 
    { 
     int res = 0; 
     mt19937 gen(1); 

     tic = clock(); 
     for(int i=0; i<N; i++) 
     { 
      int r = gen()%1000; 
      res += r; 
      res %= 1000; 
     } 
     toc = clock(); 
     cout << "simple modulus operation: "<<(float)(toc-tic)/CLOCKS_PER_SEC << endl; 
     cout<<res<<" "<<endl; 

    } 

    cout<<endl; 
} 

} 

uscita:

trial: 0 
uniform_int_distribution: 2.90289 
538 
simple modulus operation: 1.0232 
575 

trial: 1 
uniform_int_distribution: 2.86416 
538 
simple modulus operation: 1.01866 
575 

trial: 2 
uniform_int_distribution: 2.94309 
538 
simple modulus operation: 1.01809 
575 
+4

'std :: uniform_int_distribution' è in grado di generare una distribuzione uniforme tra qualsiasi intervallo intero, mentre' %' non può. – Lingxi

+19

È abbastanza facile scrivere codice veloce se non è necessario farlo correttamente. –

+6

https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful –

risposta

39

Otterrete distorsione statistica quando si utilizza modulo (%) per mappare la gamma di esempio rand() a un altro intervallo.

per esempio supponiamo rand() mappe in modo uniforme (senza pregiudizi) per [0, 32767] e si desidera associare a [0,4] fare rand() % 5. Quindi i valori 0, 1 e 2 saranno prodotti in media 6554 su 32768 volte, ma i valori 3 e 4 solo 6553 volte (in modo che 3 * 6554 + 2 * 6553 = 32768).

Il bias è piccolo (0,01%) ma dipende dall'applicazione che potrebbe rivelarsi fatale. Guarda il discorso di Stephan T. Lavavej "rand() considered harmful" per ulteriori dettagli.

+1

Per essere onesti, un corollario è che se il modulo è una potenza costante di due, allora '%' rsp. '&' può essere molto più veloce di 'uniform_int_distribution', e non viene introdotto alcun bias nelle solite implementazioni. –

+0

@ArneVogel true, ma solo se RAND_MAX è anche una potenza di 2. Questo valore dipende dall'implementazione. È garantito che questo valore è almeno 32767. Per il codice portatile e le interfacce generali, basta usare 'uniform_int_distribution'. – TemplateRex

+0

@ArneVogel Sembra un problema QOI, no? Ma, se si dispone di un numero casuale con bit X di entropia con larghezza di bit Y con diffusione dell'entropia uniforme, se si estrae i bit Z più bassi, si finisce con i bit X * Z/Y di entropia. Se invece metti tutti i bit Y nel risultato (un semplice sistema shift-xor), il tuo output può ancora avere fino a X bit di entropia (assumendo X <= Z). – Yakk