2013-07-22 10 views
6

Sono rimasto sorpreso di vedere che l'uscita di questo programma:Quanti numeri casuali usa std :: uniform_real_distribution?

#include <iostream> 
#include <random> 

int main() 
{ 
    std::mt19937 rng1; 
    std::mt19937 rng2; 
    std::uniform_real_distribution<double> dist; 

    double random = dist(rng1); 
    rng2.discard(2); 

    std::cout << (rng1() - rng2()) << "\n"; 

    return 0; 
} 

è 0 - vale a dire std::uniform_real_distribution utilizza due numeri casuali per produrre un double valore casuale nell'intervallo [0,1). Pensavo che ne avrebbe generato uno e lo avrei ridimensionato. Dopo averci pensato, immagino che questo sia dovuto al fatto che lo std::mt19937 produce inte a 32 bit e che il doppio è doppio di questa dimensione e quindi non "abbastanza casuale".

Domanda: Come faccio a trovare questo numero in modo generico, vale a dire se il generatore di numeri casuali e il tipo a virgola mobile sono tipi arbitrari?

Modifica: Ho appena notato che potrei usare std::generate_canonical invece, dato che sono interessato solo a numeri casuali di [0,1). Non sono sicuro se questo faccia la differenza.

+0

Non è possibile trovare questo genericamente. –

+2

@ R.MartinhoFernandes: perché ... – arne

+1

Per inciso, pensa a cosa significherebbe "ridimensionare" un numero intero a 32 bit in un doppio a 64 bit: ci sono circa 2^62 valori doppi distinti. Ci sono 2^32 valori int distinti. Ciò significa che solo ** un doppio su ogni ** ** possibile doppio valore sarebbe rappresentabile nel doppio risultante. Questo è chiaramente inaccettabile. – JohannesD

risposta

2

Per template<class RealType, size_t bits, class URNG> std::generate_canonical standard (sezione 27.5.7.2) definisce esplicitamente il numero di chiamate al uniforme generatore di numeri casuali (URNG) essere

max (1, b/log_2 R),

dove b è il minimo del numero di bit nella mantissa del RealType e il numero di bit assegnati a generate_canonical come parametro del template. R è l'intervallo di numeri che l'URNG può restituire (URNG::max()-URNG::min()+1). Tuttavia, nel tuo esempio questo non farà alcuna differenza, dal momento che hai bisogno di 2 chiamate al mt19937 per riempire i 53 bit della mantissa del doppio.

Per altre distribuzioni lo standard non fornisce un modo generico per ottenere informazioni su quanti numeri URNG deve generare per ottenere un numero della distribuzione.

Un motivo potrebbe essere che per alcune distribuzioni il numero uniforme di numeri casuali necessari per generare un singolo numero della distribuzione non è fisso e può variare da chiamata a chiamata. Un esempio è lo std::poisson_distribution, che di solito viene implementato come un ciclo che disegna un numero casuale uniforme in ogni iterazione finché il prodotto di questi numeri ha raggiunto una certa soglia (vedere ad esempio lo implementation of the GNU C++ library (riga 1523-1528)).