2013-04-09 8 views
5

Ich schrieb die folgende Klasse zum Generieren zufälliger Ganzzahlen aus einem bestimmten Intervall [lower, upper].Pseudo-zufällige Ganzzahlen aus einem sich ändernden Intervall effizient generieren

class RandomInteger { 

protected: 

    std::random_device randomDevice; 
    std::default_random_engine randomEngine; 
    std::uniform_int_distribution<> distribution; 

public: 

    RandomInteger(int64_t lower, int64_t upper); 

    virtual ~RandomInteger(); 

    virtual int64_t generate(); 
}; 


RandomInteger::RandomInteger(int64_t lower, int64_t upper) : randomEngine(this->randomDevice()), distribution(lower, upper) { 
} 

RandomInteger::~RandomInteger() { 
    // TODO Auto-generated destructor stub 
} 

int64_t RandomInteger::generate() { 
    int64_t i = this->distribution(this->randomEngine); 
    return i; 
} 

Das ist in Ordnung, wenn das Intervall die gleichen und mehr Anrufe zu generate bleibt bestehen. Jetzt erzeugt mein Anwendungsfall Ganzzahlen aus einem Intervall, das sich immer ändert (die obere Grenze erhöht sich jedes Mal).

In erster Linie muss dies schnell sein. Das hat nichts mit Kryptographie zu tun, also sind Pseudozufallszahlen in Ordnung (und std::random_device wird wahrscheinlich nicht benötigt). Ich möchte auch C-Stil vermeiden, wenn möglich und verwenden Sie modernen C++ 11-Stil.

Können Sie Vorschläge machen, dies effizient zu tun?

+2

Wird die Verteilung nicht effizient genug geändert? 'uniform_int_distribution' ist ein sehr dünner Wrapper, es sollte keinen signifikanten Overhead geben. Warum sind die Funktionen in Ihrer Klasse auch "virtuell"? –

+0

@KonradRudolph Sie müssen nicht virtuell sein. Würden sie, wenn sie nicht virtuell sind, hier zu erheblichen Verbesserungen führen? Ich habe gelernt, dass der Aufwand für virtuelle Methodenaufrufe sehr gering ist. Es ist eine seltsame Situation: C++ behauptet, eine OOP-Sprache zu sein. Bei OOP geht es in erster Linie darum, Ihren Code in Zukunft erweiterbar und wiederverwendbar zu machen. Viele C++ - Programmierer raten jedoch anderen ständig dazu, OOP zu deaktivieren (d. H. Methoden nicht virtuell zu machen), es sei denn, sie werden gerade jetzt explizit benötigt. – clstaudt

+0

@KonradRudolph "Ändern der Verteilung" würde bedeuten, eine neue "std :: uniform_int_distribution" mit verschiedenen Parametern zu instanziieren? – clstaudt

Antwort

2

Verwenden Sie die Überlastung von uniform_int_distribution::operator(), die ein const param_type & akzeptiert., Dass Sie sollten distribution

int64_t RandomInteger::generate(int64_t lower, int64_t upper) { 
    int64_t i = this->distribution(this->randomEngine, 
     std::uniform_int_distribution<int64_t>{lower, upper}.param()); 
    return i; 
} 

(Notenwert initialisieren, wie Sie bei der Einrichtung seiner param nicht interessiert Auch sollte distribution mit int64_t Templat werden, nicht int.)

Wenn uniform_int_distribution einen beliebigen Zustand erhält, wird dieser effizient verwendet.

In der Tat, die meisten Implementierungen von uniform_int_distribution keinen Zustand erhalten; siehe z.B. libstdC++ random.tcc: http://gcc.gnu.org/onlinedocs/gcc-4.6.0/libstdc++/api/a01001_source.html#l00832

Verwandte Themen