Jak sugeruje tytuł, próbuję wymyślić sposób generowania liczb losowych za pomocą nowej <random>
biblioteki C ++ 11 . Wypróbowałem to z tym kodem:
std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);
Problem z kodem, który mam, polega na tym, że za każdym razem, gdy go kompiluję i uruchamiam, generuje zawsze te same liczby. Więc moje pytanie brzmi: jakie inne funkcje w bibliotece losowej mogą to osiągnąć, będąc naprawdę losowymi?
W moim konkretnym przypadku próbowałem uzyskać wartość z zakresu [1, 10]
std::mt19937
jako silnika, chyba że masz dobry powód, aby tego nie robić. Dystrybucja to zamknięty przedział na obu końcach.std::uniform_int_distribution
, który jest zamknięty z obu stron.Odpowiedzi:
Stephan T. Lavavej (stl) z Microsoftu wygłosił wykład na Going Native o tym, jak używać nowych losowych funkcji C ++ 11 i dlaczego nie używać
rand()
. Umieścił w nim slajd, który zasadniczo rozwiązuje twoje pytanie. Skopiowałem kod z tego slajdu poniżej.Pełne jego wystąpienie można zobaczyć tutaj: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
Używamy
random_device
raz do zaszczepienia nazwanego generatora liczb losowychmt
.random_device()
jest wolniejszy niżmt19937
, ale nie musi być inicjowany, ponieważ żąda losowych danych z systemu operacyjnego (które będą pobierane z różnych lokalizacji, takich jak na przykład RdRand ).Patrząc na to pytanie / odpowiedź , wydaje się, że
uniform_real_distribution
zwraca liczbę z zakresu[a, b)
, w którym chcesz[a, b]
. Aby to zrobić, naszuniform_real_distibution
powinien wyglądać tak:źródło
default_random_engine
, zgodnie z podkładem c ++ jest to ten, który implementacja uznała za najbardziej użytecznądefault_random_engine
.std::default_container
, mam nadzieję, że nie ma ludzie uważający się za programistów, którzy nie znają różnic, wiele języków skryptowych ma domyślną strukturę typu mapy, którą można zaimplementować na wiele różnych sposobów, których użytkownik może nie znaćnextafter
przypadku większości aplikacji wezwanie to przesada. Szanse na losowedouble
lądowanie dokładnie na punkcie końcowym są tak małe, że nie ma praktycznej różnicy między włączeniem a wykluczeniem.std::vector
analogia nie działa tutaj, ponieważstd::vector
jest to w rzeczywistości dobra wartość domyślna z powodu buforowania procesora. Nawet przewyższa jestd::list
wkładaniem pośrodku. To prawda, nawet jeśli rozumiesz wszystkie kontenery i możesz podjąć świadomą decyzję na podstawie złożoności algorytmicznej.Moja „losowa” biblioteka zapewnia wygodne i wygodne opakowanie wokół losowych klas w C ++ 11. Możesz zrobić prawie wszystko za pomocą prostej metody „pobierz”.
Przykłady:
Losowa liczba w zakresie
Losowe wartości logiczne
Losowa wartość z listy std :: initilizer_list
Losowy iterator z zakresu iteratora lub całego kontenera
I jeszcze więcej rzeczy! Sprawdź stronę github:
https://github.com/effolkronium/random
źródło
Podpisałem wszystkie powyższe rzeczy, około 40 innych stron z c ++ w ten sposób i obejrzałem wideo Stephana T. Lavaveja "STL" i nadal nie byłem pewien, jak liczby losowe działają w praktyce, więc poświęciłem całą niedzielę, aby się dowiedzieć o co w tym wszystkim chodzi i jak to działa i może być używane.
Moim zdaniem STL ma rację co do „nieużywania już srand” i wyjaśnił to dobrze w wideo 2 . Zaleca również użycie:
a)
void random_device_uniform()
- dla zaszyfrowanego generowania, ale wolniej (z mojego przykładu)b) przykłady z
mt19937
- szybszym, możliwością tworzenia seedów, nie jest szyfrowaneWyciągnąłem wszystkie zgłoszone książki C ++ 11, do których mam dostęp, i stwierdziłem, że niemieccy autorzy, tacy jak Breymann (2015), nadal używają klonu
tylko z
<random>
zamiast<time> and <cstdlib>
#includings - więc uważaj, aby uczyć się tylko z jednej książki :).Znaczenie - tego nie należy używać od czasu C ++ 11, ponieważ:
W końcu znalazłem najlepsze wyjaśnienie z 20 nowszych książek Bjarne Stroustrupsa - a on powinien znać się na swoich rzeczach - w „Wycieczka po C ++ 2019”, „Zasady programowania i praktyka przy użyciu C ++ 2016” oraz „Język programowania C ++, wydanie 4 2014 ”, a także kilka przykładów w„ Lippmans C ++ primer piąta edycja 2012 ”:
Jest to naprawdę proste, ponieważ generator liczb losowych składa się z dwóch części: (1) silnika, który tworzy sekwencję wartości losowych lub pseudolosowych. (2) rozkład, który odwzorowuje te wartości w matematycznym rozkładzie w zakresie.
Wbrew opinii gościa z Microsoftu STL, Bjarne Stroustrups pisze:
void die_roll()
Przykład pochodzi z Bjarne Stroustrups - dobry pomysł silnik generowania i dystrybucji zusing
(bardziej że walka tutaj) .Aby móc w praktyce skorzystać z generatorów liczb losowych dostarczonych przez bibliotekę standardową,
<random>
tutaj trochę kodu wykonywalnego z różnymi przykładami zredukowanymi do najmniej potrzebnego, który, miejmy nadzieję, pozwoli wam zaoszczędzić czas i pieniądze:Myślę, że to wszystko sumuje i tak jak powiedziałem, zajęło mi sporo czytania i czasu, aby odłożyć to do tych przykładów - jeśli masz więcej rzeczy na temat generowania liczb, cieszę się, że o tym usłyszę po południu lub w sekcji komentarzy i doda go w razie potrzeby lub edytuje ten post. Bool
źródło
Oto coś, co właśnie napisałem w tych liniach:
~
źródło
Oto trochę zasobów, które możesz przeczytać o generatorze liczb pseudolosowych.
https://en.wikipedia.org/wiki/Pseudorandom_number_generator
Zasadniczo liczby losowe w komputerze wymagają ziarna (ta liczba może być bieżącym czasem systemowym).
Zastąpić
Przez
źródło
Masz dwie typowe sytuacje. Po pierwsze, chcesz liczb losowych i nie przejmujesz się jakością ani szybkością wykonywania. W takim przypadku użyj następującego makra
to daje p w zakresie od 0 do 1 - epsilon (chyba że RAND_MAX jest większe niż dokładność podwójnej, ale martw się o to, kiedy do tego dojdziesz).
int x = (int) (uniform () * N);
Teraz daje losową liczbę całkowitą od 0 do N -1.
Jeśli potrzebujesz innych dystrybucji, musisz przekształcić p. Czasami łatwiej jest kilka razy wywołać uniform ().
Jeśli chcesz, aby zachowanie było powtarzalne, zaszczepia stałą, w przeciwnym razie ziarno wywołuje time ().
Teraz, jeśli martwisz się jakością lub wydajnością w czasie wykonywania, przepisz uniform (). Ale poza tym nie dotykaj kodu. Zawsze trzymaj uniform () na 0 do 1 minus epsilon. Teraz możesz zawinąć bibliotekę liczb losowych C ++, aby utworzyć lepszy uniform (), ale jest to rodzaj opcji średniego poziomu. Jeśli przejmujesz się charakterystyką RNG, warto również poświęcić trochę czasu, aby zrozumieć, jak działają podstawowe metody, a następnie podać jedną. Masz więc pełną kontrolę nad kodem i możesz zagwarantować, że przy tym samym ziarnie sekwencja będzie zawsze dokładnie taka sama, niezależnie od platformy lub wersji C ++, z którą się łączysz.
źródło