Losowość W niektórych przypadkach klasa Random nie wystarcza do generowania losowych liczb. Problematyka generowania losowych wartości polega na tym ,że są one generowane według określonego wzoru.
Co oznacza , że tak naprawdę są one liczbami pseudolosowymi. Jeśli ten wzór nie jest dobry wtedy nasza”losowość” nie jest aż taka bardzo „losowa”.
Taka losowość jest w porządku jednak w większości przypadków wciąż nie można jej porównać do rzutu kostką, czy monetą. Przykładowo, jeśli chcemy wylosować z 10.000 użytkowników jednego za pomocą klasy Random istnieje duża szansa , że nasze losowanie z góry będzie działać na korzyść w pewnym przedziale. Sprawa jeszcze bardziej się komplikuje, gdy nasze losowania konkursowe odbywają się np. trzy razy dziennie, co oznacza ,że na dłuższą metę można byłoby określić, którzy użytkownicy najczęściej wygrywają. Jeśli chcemy przeprowadzać uczciwe konkursy i losowania to musimy stworzyć alternatywny sposób generowania losowych cyfr.
Pisanie swojego uczciwego algorytmu losowania wymaga z pewnością znajomości pewnych zagadnień matematycznych, jak i wysiłku.
My chcemy tego uniknąć dlatego skorzystamy z gotowego rozwiązania, które znajduje się na stronie: http://www.random.org/
Zaraz, zaraz, ale skąd wiemy , że ta strona nie generuje pseudolosowych liczb. Faktycznie trudno ludzkim okiem określić, co generuje losowe liczby ,a co nie.
Zgodnie z rachunkiem prawdopodobieństwa szansa wylosowania trzy razy szóstki, w trzech rzutach z rzędu wynosi jak jeden do 216. Jednak nie zmienia to faktu ,że taka szansa istnieje. Nie oznaczałoby to od razu ,że generator nie jest losowy. Podobny problem jest ukazany na ilustracji powyżej.
Nie mówiąc o tym ,że dla komputera w każdym rzucie prawdopodobieństwo wyrzucenia szóstki zawszę będzie 1/6, ponieważ rzuty nie są zależne od siebie. Nie mniej, jednak jeśli nasz algorytm losujący często się powtarzające się cyfry i łamie rachunek prawdopodobieństwa powinniśmy mu się bardziej przyjrzeć.
Jak widać obrazek z RANDOM.ORG jest ziarnisty i nie ma żadnego wzoru. Natomiast funkcja rand() z PHP widać , że wygenerowała obrazek o stałym wzorze. Z klasą Random() w .NET jest zapewne tak samo. O ile dobrze pamiętam mój wykładowca próbował to zrobić na jednej z prezentacji na konferencji ITAD w Białej Podlaskiej.
Jeśli prowadzilibyśmy gry hazardowe na podstawie te standardowe algorytmy, mielibyśmy duży problem.
Tabelka poniżej prezentuje zestawienie dwóch typów generatorów liczb losowych.
Pseudo generator liczb losowych | Prawdziwy generator liczb losowych | |
Wydajność | Znakomita | Słaba |
Deterministyczny | Deterministyczna | NieDeterministyczna |
Okresowość | Okresowa | Aperiodyczny |
Do których aplikacji które generatory.
Aplikacja | Generator |
Loteria | Prawdziwy generator liczb losowych |
Gry i hazard | Prawdziwy generator liczb losowych |
Symulacja i modelowanie | Pseudo generator liczb losowych |
Bezpieczeństwo (hasła, klucze) | Prawdziwy generator liczb losowych |
Sztuka | Oba |
Tyle, jeśli chodzi o wstęp do tematyki „losowości” wbrew pozorom jest to bardzo rozbudowana tematyka.
Jak działa serwis http://www.random.org/
W serwisie możemy ściągać różne gotowe widżety, które będą losować nam cyfry w określony sposób (np. polskie lotto)
Mogą one być później umieszczane na twojej stronie internetowej. My jednak nie chcemy skorzystać z tego serwisu i wyciągnąć z niego prawdziwe wylosowane cyfry.
Serwis oferuje nam interfejs HTTP. Przesyłając zapytanie do nich w takim formacie:
http://www.random.org/integers/?num=10&min=1&max=6&col=1&base=10&format=plain&rnd=new
Otrzymamy 10 losowych cyfr z zakresu od 1 do 6. Więcej informacji o strukturze tego zapytania można przeczytać tutaj.
Serwis ma jednak pewne ograniczenie. Po pierwsze zapytania nie mogą być przesyłana za często. Grozi to banem ,a lista zbanowanych ip-ików znajduje się tutaj.
Po drugie nie może pobrać też wiele bitów naraz. Mam też określony limit dzienny na pobranie informacji. To ile nasz IP-ik może jeszcze pobrać bitów można sprawdzić tutaj.
Trzeba pamiętać o tym, zwłaszcza jeśli korzystamy z innych funkcji tego serwisu jak generowanie losowego stringa. Osobiście dzisiaj trochę przesadziłem z testowaniem tych funkcjonalności i wyzerowałem sobie liczbę dostępnych bajtów. Średnio co 24 godziny każdy IP otrzymuje 200.000 bitów do dyspozycji. Każdy ip może maksymalnie trzymać 1.000.000 bitów. Taka jest wartość startowa.
Naturalnie możemy zakupić większą liczbę bajtów. Jednak najważniejsze jest to ,że nie musimy tutaj zakładać konta ,ani pobierać jakieś usługi. Użycie w swojej aplikacji tego serwisu jest dziecinnie proste.
Aplikacja WPF, która generuje losowe liczby
Interfejs programu wygląda tak:
Mamy tutaj przycisk, który rozpocznie losowanie, dwa textboxy, które pobiorą zakres liczby oraz prosty suwak, który określa ile liczb chcemy wylosować. Na dole znajduje się listbox, który będzie przechowywał nasze wyniki.
Kod aplikacji jest następujący:
private void button1_Click(object sender, RoutedEventArgs e)
{
int min;
bool op1ok = int.TryParse(txt_RMin.Text,out min);
int max;
bool op2ok = int.TryParse(txt_RMax.Text,out max);
if (op1ok == false || op2ok == false )
throw new ArgumentException("wrong numbers");
int hownumbers = (int)Slider.Value;
string url = @"http://www.random.org/integers/?num="+
hownumbers.ToString() +
"&min=" + min.ToString() +
"&max=" + max.ToString() +
"&col=1&base=10&format=plain&rnd=new";
try {
string data = HtmlDownload.HtmlToString(url);
string[] dataArray = data.Split('\n');
foreach (var item in dataArray)
{
listBox1.Items.Add(item);
}
}
//błedy 503 catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Nie ma tutaj niczego skomplikowanego składam zapytanie http z moich tekstówbox-ów i slidera. Później pobieram stringi, czyli losowe liczby z tego zapytania i je umieszczam w listbox.
Ściągniecie HTML musi wykonać się w try/catch, ponieważ, mimo iż możemy przestrzegać zasad użycia serwisu wciąż serwer może wyrzucić nam błąd 503.
Ok. ale co to za magiczna klasa HtmlDownload , nie ma takiej klasy w .NET. Tę klasę zapożyczyłem z gotowego kodu, który znalazłem w serwisie. Sama klasa nie jest skomplikowana wygląda ona tak.
/// <summary>
/// Methods for downloading a web-page from the internet.
/// </summary>
static class HtmlDownload
{
/// <summary>
/// Download webpage from given url-address to a StreamReader object.
/// </summary>
/// <param name="url">Internet address of web-page to download.</param>
/// <returns>StreamReader-object with web-page contents.</returns>
public static StreamReader HtmlToStream(string url)
{
WebRequest webRequest = WebRequest.Create(url);
WebResponse webResponse = webRequest.GetResponse();
StreamReader streamReader = new StreamReader(webResponse.GetResponseStream());
return streamReader;
}
/// <summary>
/// Download webpage from given url-address to a string.
/// </summary>
/// <param name="url">Internet address of web-page to download.</param>
/// <returns>String with web-page contents.</returns>
public static string HtmlToString(string url)
{
return HtmlToStream(url).ReadToEnd();
}
}
Jak też widać na obrazku poniżej operacja pobrania 7 losowych liczb z zakresu od 1 do 4000 kosztowała mnie 84 bity.
Wypadałoby, aby nasza aplikacja mogła wyświetlać liczbę dostępnych bitów. Jest to możliwe przy pomocy innego zapytania HTTP, które nic nas nie kosztuje.
http://www.random.org/quota/?format=plainAnalogicznie do poprzedniego przykładu ta funkcjonalność może być użyta w następujący sposób.
private void button2_Click(object sender, RoutedEventArgs e)
{
string url = "http://www.random.org/quota/?format=plain";
try {
string data = HtmlDownload.HtmlToString(url);
MessageBox.Show(data);
}
catch (Exception ex )
{
MessageBox.Show(ex.Message);
}
}
Miłego losowania.
Edit z 2022: Kod przeniosłem do GitHuba : PanNiebieski/RandomNumbersWPF (github.com)