Pewnie rand() % n
będąc mniej niż idealnym
Doing rand() % n
ma nierównomierny rozkład. Otrzymasz nieproporcjonalną liczbę niektórych wartości, ponieważ liczba wartości nie jest wielokrotnością 20
Następnie rand()
jest zwykle liniowym generatorem kongruencjalnym (jest wiele innych , tylko ten jest najprawdopodobniej zaimplementowany - i z parametrami mniej niż idealnymi (istnieje wiele sposobów wyboru parametrów)). Największym problemem jest to, że często małe bity (te, które otrzymujesz z % 20
wyrażeniem typu) nie są tak losowe. Pamiętam jeden rand()
z lat temu, w którym najniższy bit zmieniał się od 1
do 0
przy każdym wywołaniu do rand()
- nie był zbyt przypadkowy.
Na stronie podręcznika rand (3):
Wersje rand () i srand () w bibliotece Linux C używają tego samego
generator liczb losowych jako random () i srandom (), więc w niższej kolejności
bity powinny być tak losowe, jak bity wyższego rzędu. Jednak na starszych
implementacje rand () oraz bieżące implementacje na różnych
w systemach, bity niższego rzędu są znacznie mniej losowe niż bity wyższe
zamówić bity. Nie używaj tej funkcji w zamierzonych aplikacjach
przenośny, gdy potrzebna jest dobra losowość.
To może być teraz przeniesione do historii, ale jest całkiem możliwe, że wciąż masz słabą implementację rand () ukrytą gdzieś na stosie. W takim przypadku nadal ma to zastosowanie.
Należy użyć dobrej biblioteki liczb losowych (która daje dobre liczby losowe), a następnie poprosić o liczby losowe w żądanym zakresie.
Przykład dobrego bitu liczb losowych (od 13:00 w połączonym wideo)
#include <iostream>
#include <random>
int main() {
std::mt19937 mt(1729); // yes, this is a fixed seed
std::uniform_int_distribution<int> dist(0, 99);
for (int i = 0; i < 10000; i++) {
std::cout << dist(mt) << " ";
}
std::cout << std::endl;
}
Porównaj to z:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
for (int i = 0; i < 10000; i++) {
printf("%d ", rand() % 100);
}
printf("\n");
}
Uruchom oba te programy i porównaj, jak często określone liczby pojawiają się (lub nie pojawiają) na tym wyjściu.
Powiązane wideo: rand () uważane za szkodliwe
Niektóre historyczne aspekty rand () powodujące błędy w Nethacku, które należy obserwować i brać pod uwagę we własnych implementacjach:
Problem z Nethack RNG
Rand () jest bardzo podstawową funkcją generowania liczb losowych przez Nethacka. Sposób, w jaki Nethack go używa, jest błędny lub można argumentować, że lrand48 () produkuje kiepskie pseudolosowe liczby. (Jednak lrand48 () jest funkcją biblioteki używającą zdefiniowanej metody PRNG, a każdy program, który jej używa, powinien uwzględniać słabości tej metody.)
Błąd polega na tym, że Nethack polega (czasem wyłącznie tak, jak w przypadku rn (2)) na niższych bitach wyników z lrand48 (). Z tego powodu RNG w całej grze działa źle. Jest to szczególnie zauważalne, zanim działania użytkownika wprowadzą dalszą losowość, tj. W generowaniu postaci i tworzeniu pierwszego poziomu.
Chociaż powyższe pochodzi z 2003 roku, należy pamiętać, ponieważ może nie być tak, że wszystkie systemy z zamierzoną grą będą nowoczesnym systemem Linux z dobrą funkcją rand ().
Jeśli robisz to tylko dla siebie, możesz sprawdzić, jak dobry jest Twój generator liczb losowych, pisząc kod i testując dane wyjściowe za pomocą ent .
Na właściwości liczb losowych
Istnieją inne interpretacje „losowego”, które nie są dokładnie przypadkowe. W losowym strumieniu danych całkiem możliwe jest dwukrotne uzyskanie tej samej liczby. Jeśli rzucisz monetą (losowo), całkiem możliwe jest zdobycie dwóch głów z rzędu. Lub rzuć kostką dwa razy i uzyskaj ten sam numer dwa razy z rzędu. Lub zakręć kołem ruletki i uzyskaj dwa razy ten sam numer.
Rozkład liczb
Podczas odtwarzania listy utworów ludzie oczekują, że „losowy” będzie oznaczać, że ten sam utwór lub wykonawca nie zostanie odtworzony drugi raz z rzędu. Odtwarzanie listy odtwarzania The Beatles dwa razy z rzędu jest uważane za „nieprzypadkowe” (choć jest losowe). Postrzeganie, że dla listy odtwarzania czterech utworów odtwarzano w sumie osiem razy:
1 3 2 4 1 2 4 3
jest bardziej „losowy” niż:
1 3 3 2 1 4 4 2
Więcej informacji na temat „tasowania” utworów: jak przetasować utwory?
Na powtarzanych wartościach
Jeśli nie chcesz powtarzać wartości, należy rozważyć inne podejście. Wygeneruj wszystkie możliwe wartości i potasuj je.
Jeśli dzwonisz rand()
(lub jakikolwiek inny generator liczb losowych), dzwonisz do niego z zastępstwem. Zawsze możesz uzyskać ten sam numer dwa razy. Jedną z opcji jest ciągłe wyrzucanie wartości, dopóki nie wybierzesz tej, która spełnia twoje wymagania. Zwrócę uwagę, że ma to nieokreślony czas działania i możliwe jest, że znajdziesz się w sytuacji, w której istnieje nieskończona pętla, chyba że zaczniesz wykonywać bardziej złożone śledzenie wstecz.
Lista i wybór
Inną opcją jest wygenerowanie listy wszystkich możliwych poprawnych stanów, a następnie wybranie losowego elementu z tej listy. Znajdź wszystkie puste miejsca (spełniające pewne zasady) w pokoju, a następnie wybierz losowe z tej listy. A potem rób to wielokrotnie, aż skończysz.
Człapać
Drugim podejściem jest tasowanie, jakby była to talia kart. Zacznij od wszystkich pustych miejsc w pokoju, a następnie zacznij przypisywać je, przydzielając puste miejsca, po jednym na raz, każdej regule / procesowi prosząc o puste miejsce. Skończysz, gdy zabraknie Ci kart lub przestaniesz o nie pytać.