2013-03-19 10 views
40

Przeczytałem, że wiele generatorów liczb pseudolosowych wymaga wielu próbek w zamówieniu, aby je "rozgrzać". Czy tak jest w przypadku użycia std :: random_device do rozsiewania std :: mt19937, czy możemy oczekiwać, że będzie gotowy po zakończeniu budowy? Kod w pytaniu:Czy std :: mt19937 wymaga rozgrzewania?

#include <random> 
std::random_device rd; 
std::mt19937 gen(rd()); 
+7

Gdzie można przeczytać, że? Nigdy o tym nie słyszałem, wiem tylko, że powinny być rozstawione ... – PlasmaHH

+0

Na przykład w tej pracy jest trochę dyskusji: http://www0.cs.ucl.ac.uk/staff/d. jones/GoodPracticeRNG.pdf – Brent

+1

Dla większości PRNG nie ma to żadnego sensu. Siew wyznacza stan wewnętrzny, a każde "rozgrzanie" permutuje stan wewnętrzny, ponieważ ma taki sam efekt, gdy ten nowy stan został wybrany jako nasiono. – PlasmaHH

Odpowiedz

51

Mersenne Twister to zmiana PRNG (generator liczb pseudolosowych) i dlatego jest podatny na złe nasiona z długimi seriami zer lub jedynek, które prowadzą do względnie przewidywalnych wyników, dopóki stan wewnętrzny nie zostanie wystarczająco zmiksowany.

Jednak konstruktor, który przyjmuje jedną wartość, wykorzystuje skomplikowaną funkcję dla tej wartości początkowej, która ma na celu zminimalizowanie prawdopodobieństwa wystąpienia takich "złych" stanów. Istnieje drugi sposób inicjowania mt19937, w którym bezpośrednio ustawiasz stan wewnętrzny, poprzez obiekt zgodny z koncepcją SeedSequence. Jest to druga metoda inicjowania, w której może być konieczne rozważenie wyboru "dobrego" stanu lub rozgrzewki.


Norma obejmuje obiekt zgodny z koncepcją SeedSequence, o nazwie seed_seq. seed_seq pobiera dowolną liczbę wejściowych wartości początkowych, a następnie wykonuje określone operacje na tych wartościach w celu utworzenia sekwencji różnych wartości odpowiednich do bezpośredniego ustawienia wewnętrznego stanu pRNG.

Oto przykład ładuje się sekwencję nasion z dość przypadkowych danych, aby wypełnić całą std::mt19937 stan:

std::array<int, 624> seed_data; 
std::random_device r; 
std::generate_n(seed_data.data(), seed_data.size(), std::ref(r)); 
std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); 

std::mt19937 eng(seq); 

To gwarantuje, że cały stan jest randomizowane. Ponadto każdy silnik określa, ile danych odczytuje z sekwencji seed_, więc możesz przeczytać dokumenty, aby znaleźć te informacje dla dowolnego używanego silnika.

Chociaż tutaj ładuję seed_seq całkowicie od std::random_device, seed_seq jest określony tak, że tylko kilka liczb, które nie są przypadkowe, powinno działać poprawnie. Na przykład:

std::seed_seq seq{1, 2, 3, 4, 5}; 
std::mt19937 eng(seq); 

W komentarzach poniżej Cubbi wskazuje, że seed_seq prace wykonując sekwencję nagrzewania dla Ciebie.

Oto co powinno być twoim „default” siewna:

std::random_device r; 
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; 
std::mt19937 rng(seed); 
+2

Przypadkowo, domyślne C++ 11 'seed_seq' * jest * sekwencją rozgrzewającą Mersenne Twister (chociaż istniejące implementacje, na przykład libC++' mt19937', używają prostszej rozgrzewki, gdy dostarczane jest ziarno o pojedynczej wartości) – Cubbi

+1

'Std :: generate_n' generuje SDL Warning C4996 na nowszych kompilatorach MSVC, więc możesz użyć 'std :: generate (seed_data.begin(), seed_data.end(), std :: ref (r));'. – NightElfik

+0

Czy można bezpiecznie założyć, że "state_size" generatora jest zawsze wyrażane w wielokrotności 'sizeof (int)'? Jeśli na przykład generator miał wartość 'state_size' zmierzoną w bajtach, tablica' seed_data' byłaby zbyt duża. – Wyzard

2

Wierzę, że istnieją sytuacje, w których może być rozstawiony MT „słabo”, co skutkuje nieoptymalnych sekwencji. Jeśli dobrze pamiętam, jednym z takich przypadków jest zasianie wszystkimi zerami. Polecam spróbować użyć generatorów WELL, jeśli jest to poważny problem. Uważam, że są bardziej elastyczne - jakość nasion nie ma większego znaczenia. (Być może, aby odpowiedzieć na to pytanie bardziej bezpośrednio: prawdopodobnie lepiej jest skupić się na dobrze wysiewaniu niż na słabym wysiewaniu, a następnie próbować wygenerować kilka próbek, aby uzyskać optymalny stan generatora.)

Powiązane problemy