2013-09-26 11 views
19

Così ho un oggetto a caso:Vary gamma di uniform_int_distribution

typedef unsigned int uint32; 

class Random { 
public: 
    Random() = default; 
    Random(std::mt19937::result_type seed) : eng(seed) {} 

private: 
    uint32 DrawNumber(); 
    std::mt19937 eng{std::random_device{}()}; 
    std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX}; 
}; 

uint32 Random::DrawNumber() 
{ 
    return uniform_dist(eng); 
} 

Qual è il modo migliore che posso variare (tramite un'altra funzione o in altro modo) il limite superiore della distribuzione?

(anche disposti a prendere consigli su altre questioni di stile)

+0

Non è possibile variare i limiti della 'distribution' dopo la prima di loro l'inizializzazione. Il modo in cui dovresti procedere dipende molto da cosa usi i tuoi numeri casuali e perché hai bisogno di cambiare i limiti. – us2012

risposta

32

oggetti di distribuzione sono leggeri. Costruisci semplicemente una nuova distribuzione quando hai bisogno di un numero casuale. Uso questo approccio in un motore di gioco e, dopo il benchmarking, è paragonabile all'utilizzo del buon vecchio rand().

Inoltre, ho chiesto come variare l'intervallo di distribuzione su GoingNative 2013 live stream, e Stephen T. Lavavej, membro del comitato standard, ha suggerito di creare semplicemente nuove distribuzioni, in quanto non dovrebbe essere un problema di prestazioni.

Ecco come vorrei scrivere il codice:

using uint32 = unsigned int; 

class Random { 
public: 
    Random() = default; 
    Random(std::mt19937::result_type seed) : eng(seed) {} 
    uint32 DrawNumber(uint32 min, uint32 max); 

private:   
    std::mt19937 eng{std::random_device{}()}; 
}; 

uint32 Random::DrawNumber(uint32 min, uint32 max) 
{ 
    return std::uniform_int_distribution<uint32>{min, max}(eng); 
} 
+0

Penso di aver visto il flusso Going Native :) Anche se, sono (un po ') nuovo di C++ (specialmente C++ 11) e una buona parte di esso è andato oltre la mia testa: L Se sei sicuro che non ci sia un sovraccarico significativo nella creazione di una nuova distribuzione ogni volta, probabilmente andrò con questo – LordAro

+0

che ho messo a confronto. L'overhead è minimo e può essere ignorato. (Questo è stato detto da un micro-ottimizzazione nazista). Inoltre, non c'è * nessun altro modo * di modificare i limiti di una distribuzione. –

+0

Ok, fantastico, grazie mille :) Probabilmente andrò con una costante 0 come minima e UINT32_MAX come predefinita per max. – LordAro

5

sto facendo la funzione publicDrawNumber per il mio esempio. È possibile fornire un overload che accetta un limite superiore, e poi passare un nuovo uniform_int_distribution::param_type per uniform_int_distribution::operator()

Il param_type possono essere costruiti utilizzando gli stessi argomenti corrispondente distribuzione.

Da N3337, §26.5.1.6/9 [rand.req.dist]

Per ciascuno dei costruttori di D prendono argomenti corrispondenti ai parametri della distribuzione, P avranno un costruttore corrispondente soggetto agli stessi requisiti e con argomenti identici in numero, tipo e valori predefiniti. Inoltre, per ciascuna delle funzioni membro di D che restituiscono valori corrispondenti ai parametri della distribuzione, P deve avere una funzione membro corrispondente con nome, tipo e semantica identici.

dove D è il tipo di un oggetto funzione di distribuzione di numeri casuali e P è il tipo nominato da D 's associato param_type

#include <iostream> 
#include <random> 

typedef unsigned int uint32; 

class Random { 
public: 
    Random() = default; 
    Random(std::mt19937::result_type seed) : eng(seed) {} 

    uint32 DrawNumber(); 
    uint32 DrawNumber(uint32 ub); 

private: 
    std::mt19937 eng{std::random_device{}()}; 
    std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX}; 
}; 

uint32 Random::DrawNumber() 
{ 
    return uniform_dist(eng); 
} 

uint32 Random::DrawNumber(uint32 ub) 
{ 
    return uniform_dist(eng, decltype(uniform_dist)::param_type(0, ub)); 
} 

int main() 
{ 
    Random r; 
    std::cout << r.DrawNumber() << std::endl; 
    std::cout << r.DrawNumber(42) << std::endl; 
} 
8

Si può semplicemente creare un std::uniform_int_distribution<uint32>::param_type e modificare l'intervallo utilizzando il param() metodo. È possibile ridurre il rumore di modello con decltype:

decltype(uniform_dist.param()) new_range (0, upper); 
uniform_dist.param(new_range);