Niedawno natknąłem się na nowy sposób generowania liczb losowych w C ++ 11, ale nie mogłem przetrawić artykułów, które o nim czytałem (co to za silnik , termin matematyczny taki jak dystrybucja , „gdzie wszystkie uzyskane liczby całkowite są równie prawdopodobne ”).
Więc czy ktoś może wyjaśnić
- czym oni są?
- co to znaczy
- jak wygenerować?
- jak oni pracują?
- itp
Możesz to nazwać w jednym FAQ dotyczącym generowania liczb losowych.
rand
, powinieneś rzucić okiem na wikipedię, aby zapoznać się z podstawowymi pojęciami dotyczącymi statystyk i liczb losowych, w przeciwnym razie naprawdę trudno będzie wyjaśnić uzasadnienie<random>
i zastosowanie różnych elementów.Odpowiedzi:
Pytanie jest o wiele za szerokie, aby dać pełną odpowiedź, ale pozwól mi wybrać kilka interesujących punktów:
Dlaczego „równie prawdopodobne”
Załóżmy, że masz prosty generator liczb losowych, który generuje liczby 0, 1, ..., 10 z jednakowym prawdopodobieństwem (pomyśl o tym jak o klasycznym
rand()
). Teraz potrzebujesz losowej liczby z zakresu 0, 1, 2, z równym prawdopodobieństwem. Twoja odruchowa reakcja byłaby wziętarand() % 3
. Ale czekaj, reszta 0 i 1 występuje częściej niż reszta 2, więc to nie jest poprawne!Dlatego potrzebujemy odpowiednich rozkładów , które pobierają źródło jednakowych losowych liczb całkowitych i zamieniają je w nasz pożądany rozkład, jak
Uniform[0,2]
w przykładzie. Najlepiej zostaw to w dobrej bibliotece!Silniki
Zatem sercem całej losowości jest dobry generator liczb pseudolosowych, który generuje sekwencję liczb, które są równomiernie rozłożone w pewnym przedziale i które idealnie mają bardzo długi okres. Standardowa implementacja
rand()
często nie jest najlepsza, dlatego warto mieć wybór. Liniowo-przystający i twister Mersenne to dwa dobre wybory (LG jest w rzeczywistości często używany również przezrand()
); znowu dobrze jest pozwolić bibliotece się tym zająć.Jak to działa
Łatwe: najpierw skonfiguruj silnik i uruchom go. Ziarno w pełni określa całą sekwencję liczb „losowych”, więc a) użyj za
/dev/urandom
każdym razem innego (np. Pobranego z ) i b) zapisz ziarno, jeśli chcesz odtworzyć sekwencję losowych wyborów.Teraz możemy tworzyć dystrybucje:
... i użyj silnika do tworzenia liczb losowych!
Konkurencja
Jeszcze jeden ważny powód, aby preferować
<random>
tradycyjnerand()
wątki, jest to, że teraz jest bardzo jasne i oczywiste, jak sprawić, by generowanie liczb losowych było bezpieczne: albo zapewnij każdemu wątkowi własny silnik lokalny dla wątku, zapoczątkowany na lokalnym źródle wątku lub zsynchronizuj dostęp do obiektu silnika.Różne
result_type
wpisać f a , który jest prawidłowym typem całki do użycia dla nasienia. Chyba miał buggy realizację raz który zmusił mnie zmusić do materiału siewnegostd::mt19937
, abyuint32_t
na x64, w końcu to powinno być stałe i można powiedzieć,MyRNG::result_type seed_val
a tym samym sprawiają, że silnik bardzo łatwo wymienialne.źródło
std::random_device
warto wspomnieć o części „Jakoś/dev/urandom
std::random_device
można znaleźć tutaj .Generator liczb losowych to równanie, które po podaniu liczby da nową liczbę. Zazwyczaj podajesz pierwszą liczbę lub jest ona pobierana z czegoś w rodzaju czasu systemowego.
Za każdym razem, gdy poprosisz o nową liczbę, używa poprzedniej liczby do wykonania równania.
Generator liczb losowych nie jest uważany za bardzo dobry, jeśli ma tendencję do generowania tej samej liczby częściej niż inne liczby. tj. jeśli chcesz losową liczbę od 1 do 5 i masz następujący rozkład liczb:
2 jest generowany znacznie częściej niż jakakolwiek inna liczba, więc jest bardziej prawdopodobne, że zostanie wygenerowany niż inne liczby. Gdyby wszystkie liczby były takie same, miałbyś 20% szans na otrzymanie każdej liczby za każdym razem. Mówiąc inaczej, powyższy rozkład jest bardzo nierównomierny, ponieważ preferowane jest 2. Rozkład ze wszystkimi 20% byłby równy.
Zwykle, jeśli chcesz uzyskać prawdziwą liczbę losową, powinieneś pobrać dane z czegoś takiego jak pogoda lub inne naturalne źródło, a nie z generatora liczb losowych.
źródło