2013-04-09 16 views
5

Napisałem następującą klasę do generowania losowych liczb całkowitych z danego przedziału [lower, upper].Generowanie pseudolosowych liczb całkowitych z efektywnego przedziału czasowego

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; 
} 

To jest w porządku, jeśli przerwa pozostaje takie same, a wiele połączeń do generate są wykonane. Jednak teraz moim przypadkiem użycia jest generowanie liczb całkowitych z przedziału, który zawsze się zmienia (górna granica rośnie za każdym razem).

Przede wszystkim musi to być szybkie. Nie ma to nic wspólnego z kryptografią, więc bardzo pseudolosowe numery są w porządku (i std::random_device prawdopodobnie nie jest potrzebne). Chciałbym również, jeśli to możliwe, unikać stylu C i używać nowoczesnego stylu C++ 11.

Czy możesz zaproponować sposób, aby to zrobić skutecznie?

+2

Czy zmiana dystrybucji nie jest wystarczająco wydajna? "uniform_int_distribution" jest bardzo cienkim opakowaniem, nie powinno być żadnego znaczącego narzutu. Dlaczego funkcje w twojej klasie są "wirtualne"? –

+0

@KonradRudolph Oni nie muszą być wirtualni. Czy sprawienie, by były one niewirtualne, przyniosłyby tutaj znaczne przyspieszenie? Nauczyłem się, że obciążenie związane z wirtualnymi wywołaniami metod jest bardzo niskie. To dziwna sytuacja: C++ twierdzi, że jest językiem OOP. OOP bardzo zależy od tego, aby Twój kod był rozszerzalny i możliwy do ponownego użycia w przyszłości. Jednak wielu programistów C++ nieustannie doradza innym, aby wyłączyć OOP (tj. Uczynić metody niewirtualnymi), chyba że jest to wyraźnie potrzebne teraz. – clstaudt

+0

@KonradRudolph "zmiana dystrybucji" oznaczałaby utworzenie nowej 'std :: uniform_int_distribution' z różnymi parametrami? – clstaudt

Odpowiedz

2

pomocą przeciążenie uniform_int_distribution::operator() która akceptuje const param_type &.

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; 
} 

(Zauważ, że należy cenić zainicjować distribution, jak nie jesteś zainteresowany w tworzeniu jego param Również distribution należy matrycy z int64_t, nie int.)

Jeśli uniform_int_distribution zachowuje dowolny stan, to użyje go wydajnie.

W rzeczywistości większość implementacji uniform_int_distribution nie zachowuje żadnego stanu; patrz np. libstdC++ random.tcc: http://gcc.gnu.org/onlinedocs/gcc-4.6.0/libstdc++/api/a01001_source.html#l00832

Powiązane problemy