2015-09-23 19 views
5

Ho provato questo programma con libstdC++, libC++ e Dinkumware:uscita a caso diverso tra le implementazioni

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

int main() 
{ 
    std::vector<int> v(10); 

    std::mt19937 rand{0}; 
    std::uniform_int_distribution<> dist(
     1, 10 
    ); 

    std::generate_n(v.begin(), v.size(), 
     std::bind(dist, rand)); 

    for (auto i : v) 
     std::cout << i << " "; 
} 

uscita rispettivamente è:

6 6 8 9 7 9 6 9 5 7 

6 1 4 4 8 10 4 6 3 5 

5 10 4 1 4 10 8 4 8 4 

L'uscita è costante per ogni esecuzione, ma, come si può vedi, sono diversi. Spiegare?

+4

Perché ci si aspetta implementazioni diffrenti di * generazione di numeri casuali * per produrre valori uguali? – lisyarus

+6

Spiegare * cosa *? Coerenza tra le corse? O incoerenza tra le implementazioni?Diverse implementazioni sono autorizzate a produrre sequenze pseudo-casuali diverse dallo stesso seme. Questo è esattamente ciò che hai osservato. – AnT

+0

Lo stesso algoritmo dovrebbe produrre gli stessi valori dati lo stesso seme, non dovrebbe? I tuoi argomenti non hanno senso. – user5368921

risposta

7

C'è no implementazione richiesta per uniform_int_distribution<>. [Rand.dist.general] precisa che:

Gli algoritmi per produrre ciascuna delle distribuzioni specificati sono definiti dall'implementazione.

Tutti che [rand.dist.uni.int] stati sono:

Un uniform_int_distribution casuale distribuzione numerica produce interi casuali i, a <= i <= b, distribuiti secondo la costante funzione di probabilità discreta P(i | a, b) = 1/(b − a + 1).

Ogni implementazione è gratuita per ottenere questa distribuzione come desidera. Quello che stai vedendo è apparentemente tre diverse implementazioni.

+0

Wow. Questo è estremamente intuitivo. Mi sarei anche aspettato che, dato lo stesso seme, il valore di ogni chiamata consecutiva fosse ben definito. Quale algoritmo di numero casuale C++ 11 definisce quel comportamento (se esiste)? – David

+0

Lo standard definisce come implementare mersenne twister in '[rand.eng.mers]'. – user5368921

+0

@ user5368921 Sì, ha iniziato il buco sbagliato. – Barry

2

Per essere chiari: i generatori di numeri casuali stessi sono specificati in modo piuttosto preciso, inclusi i parametri di input ei risultati. Per essere tecnico, ciò che viene specificato è il 10000 th risultato da un generatore predefinito, ma per qualsiasi scopo pratico una corrispondenza su questo risultato da un generatore che è almeno ragionevolmente vicino a correggere altrimenti essenzialmente garantisce che il generatore funzioni correttamente, e le sue uscite corrisponderanno a qualsiasi altro generatore simile per un dato seme.

Ad esempio, un test rapido:

#include <random> 
#include <iostream> 

int main() { 
    std::mt19937 r; 

    for (int i=0; i<10000-2; i++) 
     r(); 
    for (int i=0; i<3; i++) 
     std::cout << r() << "\n"; 
} 

... mostra risultati identici con ogni (recente) compilatore Ho pratico:

1211010839 
4123659995 
725333953 

Il secondo di questi tre è il valore richiesto dallo standard.

Tuttavia, nei modelli di distribuzione viene fornito più margine di manovra. A uniform_int_distribution deve mappare gli ingressi alle uscite in modo uniforme, ma ci sono diversi modi per farlo e nessun requisito su quale di questi modi usare.

Se è davvero necessario produrre una sequenza di numeri interi all'interno di un intervallo non solo distribuito uniformemente, ma coerente tra le implementazioni, probabilmente sarà necessario implementare il proprio codice di distribuzione. Fare questo bene non è così banale come la maggior parte delle persone inizialmente pensa. Si potrebbe voler guardare uno dei miei previous answers per un'implementazione funzionante con alcune spiegazioni e un po 'di codice di test.

Problemi correlati