Załóżmy, że chcesz korzystać z narzędzi C ++ <random>
w praktycznym programie (dla pewnej definicji „praktyczny” - ograniczenia tutaj są swego rodzaju częścią tego pytania). Masz mniej więcej taki kod:
int main(int argc, char **argv) {
int seed = get_user_provided_seed_value(argc, argv);
if (seed == 0) seed = std::random_device()();
ENGINE g(seed); // TODO: proper seeding?
go_on_and_use(g);
}
Moje pytanie brzmi: do jakiego rodzaju należy używać ENGINE
?
Zawsze mówiłem,
std::mt19937
bo szybko pisałem i rozpoznawałem nazwy. Ale w dzisiejszych czasach wydaje się, że wszyscy mówią, że Mersenne Twister jest bardzo ciężki i nieprzyjazny dla pamięci podręcznej i nie przechodzi nawet wszystkich testów statystycznych, które przeprowadzają inni.Chciałbym powiedzieć,
std::default_random_engine
ponieważ to oczywiste „domyślne”. Ale nie wiem, czy różni się w zależności od platformy i nie wiem, czy jest to statystycznie dobre.Ponieważ każdy jest na platformie 64-bitowej te dni, powinniśmy być przynajmniej przy użyciu
std::mt19937_64
ponadstd::mt19937
?Chciałbym powiedzieć
pcg64
lubxoroshiro128
dlatego, że wydają się szanowani i lekcy, ale w ogóle ich nie ma<random>
.Nie wiem nic na temat
minstd_rand
,minstd_rand0
,ranlux24
,knuth_b
na pewno muszą być dobre dla czegoś -, itd.?
Oczywiście istnieją tutaj pewne konkurencyjne ograniczenia.
Wytrzymałość silnika. (
<random>
nie ma silnie kryptograficznie PRNG, ale niektóre ze standardowych są „słabsze” niż inne, prawda?)sizeof
silnik.Szybkość jego
operator()
.Łatwość siewu.
mt19937
jest bardzo trudne do prawidłowego zaszczepienia, ponieważ ma tyle stanu do zainicjowania.Przenośność między dostawcami bibliotek. Jeśli jeden sprzedawca
foo_engine
wytwarza inne numery od innegofoo_engine
, nie jest to dobre dla niektórych aplikacji. (Mam nadzieję, że nie wyklucza to niczego opróczdefault_random_engine
.)
Biorąc pod uwagę wszystkie te ograniczenia najlepiej, jak potrafisz, co powiedziałbyś, że jest najlepszą odpowiedzią na „pozostawanie w standardowej bibliotece”? Czy powinienem po prostu dalej używać std::mt19937
, czy co?
Odpowiedzi:
C ++ Reference zawiera listę wszystkich losowych silników obecnie udostępnianych przez C ++. Jednak wybór silników pozostawia wiele do życzenia (np. Zobacz moją listę losowych generatorów wysokiej jakości ). Na przykład:
default_random_engine
jest zdefiniowany w implementacji, więc nie wiadomo, czy silnik ma wady statystyczne, na których aplikacja może mieć znaczenie.linear_congruential_engine
wdraża liniowe generatory kongruencjalne. Mają jednak niską jakość, chyba że moduł jest pierwszy i bardzo duży (co najmniej 64 bity). Nie mogą też przyjąć większej liczby nasion niż ich moduł.minstd_rand0
iminstd_rand
przyznać tylko około 2 ^ 31 nasion.knuth_b
owijaminstd_rand0
i wykonuje losowanie Baysa-Durhama.mt19937
imt19937_64
mogliby przyznać o wiele więcej nasion, gdyby były lepiej zainicjalizowane (np. przez zainicjowaniestd::seed_seq
z wieloma wyjściamirandom_device
, a nie tylko jednym), ale używają około 2500 bajtów stanu.ranlux24
iranlux48
używają około 577 bitów stanu, ale są one powolne (działają, utrzymując niektóre i odrzucając inne pseudolosowe dane wyjściowe).Jednak C ++ ma również dwa silniki, które owijają inny silnik, aby potencjalnie poprawić jego właściwości losowości:
discard_block_engine
odrzuca niektóre dane wyjściowe danego silnika losowego.shuffle_order_engine
implementuje losowanie Baysa-Durhama danego silnika losowego.Na przykład, możliwe jest, powiedzmy, aby mieć Bays-Durham shuffle
mt19937
,ranlux24
albo zwyczajulinear_congruential_engine
zshuffle_order_engine
. Być może owinięty silnik jest lepszej jakości niż oryginalny. Trudno jednak przewidzieć statystyczną jakość nowego silnika bez testowania .Dlatego w oczekiwaniu na takie testy wydaje się, że
mt19937
jest to obecnie najbardziej praktyczny silnik w standardzie C ++. Mam jednak świadomość co najmniej jednej propozycji dodania kolejnego silnika liczb losowych do przyszłych wersji C ++ (patrz artykuł C ++ P2075 ).źródło
Według C ++ Reference ,
default_random_engine
:Więc do lekkiego użytkowania nie musisz się o nic martwić,
default_random_engine
z nasionamiEpoch Time (time(0))
i to by było w porządku;)źródło