Liczby losowe w C ++

12

Niedawno przyzwyczaiłem się do współczesnych języków, w tym dobrego generatora losowego, którym zwykle jest Twister Mersenne; teraz, gdy wróciłem do C ++, muszę zdecydować, którego użyć.

Szukałem implementacji Mersenne Twister i zauważyłem, że jest ich tak wiele: czy jest taka, która jest bardziej używana i rozpowszechniona, czy też mam wybrać jedną, zakładając, że wszystkie są równie dobre?

o0 ”.
źródło
1
Podoba mi się twoje oddzielenie C ++ i języków współczesnych.
jcora
2
Może powiedzenie „wyższy poziom” było bardziej odpowiednie.
o0 ”.
Myślę, że to pytanie należy do stackoverflow
TravisG,
5
W przypadku SO podam inną odpowiedź, ponieważ nie wiedziałbym, że dotyczy to silnika gry, w przeciwieństwie do, powiedzmy, symulacji Monte Carlo do terapii medycznych, w którym to przypadku brak 624 wymiarów losowości może być śmiertelny.

Odpowiedzi:

19

C ++ 11 domyślnie zawiera generator Mersenne Twister jako część nowego <random>interfejsu. Na przykład, aby równomiernie generować liczby całkowite między [-10, 10] przy użyciu MT:

std::mt19937 eng; // This is the Mersenne Twister
std:::uniform_int_distribution<int> dist(-10, 10)
for (int i = 0; i < 10; ++i)
    std::cout << dist(eng) << std::endl;

Większość tego jest również dostępna w dowolnym kompilatorze oferującym TR1, chociaż nazwy są nieco inne; std::tr1::mt19937a std::tr1::uniform_int<int>.

Zazwyczaj ostrzegam ludzi przed używaniem Mersenne Twister. Algorytm jest w porządku, ale duża część jego popularności to tylko marketing. 624 wymiary losowości są więcej, niż potrzeba większości ludzi, a MT niesie ze sobą stosunkowo wysokie wymagania dotyczące stanu, a po ponownym przeliczeniu pełnej tabeli może zdmuchnąć pamięć podręczną. Osobiście jestem zwolennikiem xorshift, który zapewnia doskonałe okresy i rozsądną dystrybucję wszystkiego, czego potrzebuje gra, z niewielkimi wymaganiami dotyczącymi pamięci i procesora.

Napisałem (głównie?) Zgodny z C ++ 11 xorshift generator - xorshift.hpp , xorshift.cpp - i umieściłem go w domenie publicznej. Możesz podłączyć to do dowolnej funkcji randomizacji C ++ 11, jak wyżej:

xorshift eng;
std:::uniform_int_distribution<int> dist(-10, 10)
for (int i = 0; i < 10; ++i)
    std::cout << dist(eng) << std::endl;

źródło
5
Tak, takiej odpowiedzi szukałem, dlatego zamieściłem tutaj na gamedev
:)
1
Chciałem tylko zauważyć, że nic w połączonych plikach nie wskazuje, że należą one do domeny publicznej. Sposób, w jaki działa prawo autorskie, naprawdę musi być wyraźnie zaznaczony, ponieważ prawo domyślnie zakłada „wszelkie prawa zastrzeżone”. Jeszcze bezpieczniej jest po prostu użyć czegoś takiego jak licencja 2-klauzulowa MIT lub BSD, ponieważ niektóre jurysdykcje zasadniczo nie uznają, że „jest to domena publiczna” jako prawnie wiążąca. Jeśli chcesz zobaczyć, jak ludzie używają Twojego kodu, warto się tym zająć.
Sean Middleditch,
1
@seanmiddleditch: Mówię o tym właśnie tutaj. Jeśli chcesz na licencji MIT, pójdę za przykładem SQLite i dam ci to za jedyne 1000 $.
Głównym problemem jest brak nagłówka w kodzie deklarującym cokolwiek (co robi SQLite, iirc). Jeśli cię to nie obchodzi, to świetnie. Dałem ci tylko przyjazną sugestię.
Sean Middleditch
1

Innym RNG, którego użyłem wcześniej do celów gamedev, jest opisany tutaj „mały” RNG Boba Jenkinsa .

(Ma również RNG o sile kryptograficznej o nazwie ISAAC, ale jest większy i wolniejszy, a gry nie potrzebują takiego poziomu siły).

Nathan Reed
źródło
1
To wygląda drożej niż xorshift (4 xors i 3 zmiany vs. 4 dodania, 6 zmian, 2 orki i xor), ma gorszy okres i wiąże się z ryzykiem bardzo krótkich cykli z pewnymi inicjalizacjami. Wygląda szybko, ale nie najszybciej; OK okres, ale nigdzie nie jest optymalny; te same podstawowe cechy dystrybucji, co xorshift; Nie widzę żadnego powodu, aby z niego korzystać.
Słusznie. Nie wiem wystarczająco dużo o analizie RNG, aby zagłębić się w właściwości rozkładu i cyklu.
Nathan Reed