Programowanie w C Wartości pseudolosowe i pomiar czasu Artur Opaliński (pokój E112) e-mail: (p. wykład administracyjny) URL: (p. wykład administracyjny)
Treść wykładu Generowanie wartości losowych Wartości pseudolosowe i losowe w komputerze Pomiar czasu 2
Support for Yoda Master Slajdy nie były przygotowane z myślą o samodzielnej nauce. Przyjdź na wykład, żeby je lepiej zrozumieć! Zdobądź punkty bonusowe: Korzystając z informacji z wykładu, Internetu, własnych doświadczeń, itp. - opisz myśli z tej prezentacji dokładniej i złóż na Wiki! Zaznacz, które numery slajdów omawiasz 3
Wartości pseudolosowe Niekiedy potrzeba wytworzyć przypadkowe dane Kierunek ruchu przeciwnika na ekranie Prawdopodobieństwo zdarzenie, np. że pojawi się bomba W pliku nagłówowym stdlib.h zadeklarowana jest funkcja rand() o prototypie: int rand(void); Funkcja zwraca wartości int od 0 do RAND_MAX RAND_MAX to stała zdefiniowana w stdlib.h (w Windows ma wartość 32767) Przykładowe wywołanie: #include<stdlib.h> int p; p=rand(); /* p uzyska wartość pseudolosową od 0 do RAND_MAX. Jak uzyskać wartość z mniejszego zakresu? */ 4
Wartości pseudolosowe Korekta zakresu Często potrzebna jest wartość losowa z pewnego zakresu, np. 0...100, albo -10...+10 Wymaga zmiany przedziału (0,RAND_MAX) na (a,b) Długości przedziału z RAND_MAX na b-a Początku przedziału z 0 na a 0 RAND_MAX a b 5
Wartości pseudolosowe Korekta zakresu (c.d.) Metoda błędna ograniczenia zakresu p=rand() % 11 ; //np. liczby od 0 do +10: p=rand() % RANGE; // liczby od 0 do (RANGE-1) Nie nadaje się do (RANGE-1)>RAND_MAX (=rozszerzenia zakresu) Jeżeli RANGE nie mieści się całkowitą ilość razy w RAND_MAX+1, to częściej pojawią się liczby z przedziału [0, (RAND_MAX % RANGE)) niż z przedziału [(RAND_MAX % RANGE), RANGE) Pomija wpływ starszych bitów zwracanych przez rand(). Z kolei same młodsze bity w typowych generatorach pseudolosowych wykazują wyraźną powtarzalność 0 RAND_MAX 0 RANGE 6
Wartości pseudolosowe Korekta zakresu (c.d.) Metoda lepsza: p=10 + rand() / (float(rand_max)+1)* 20; //liczby [- 10;+10) p=a + rand() / (float(rand_max)+1)* (b-a); //liczby [a;b) Pozostaje problem, gdy (b-a) jest bliskie RAND_MAX i gdy (b-a) nie mieści się całkowitą ilość razy w RAND_MAX+1 0 RAND_MAX a b 7
DEMO: Generowanie wartości pseudo- losowych (w2.c) #include <stdio.h> #include <conio.h> #include <stdlib.h> // definiuje funkcję rand() i stałą RAND_MAX #define N 5000 int main() { int tab[n]={0}; // dla jasności demonstracji na pocz. same zera int i; for(i=n-1; i>=0; i--) { // inicjalizacja moze być tez od końca tab[i]=rand(); // funkcja rand() zwraca liczbę pseudolosowa printf("wartosc na pozycji %u to: %d\n", i, tab[i]); } printf("\nczy powyzej sa wartosci losowe? :-)\n"); getch(); } 8
Pseudolosowość a losowość Komputer działa deterministycznie, i wymaga źródeł losowości (entropii) do generacji liczb losowych Dobre źródła entropii Rozpad atomów Zjawiska pogodowe (http://random.org) Przeciętne źródła entropii Ruch sieciowy Aktywność użytkownika Czas działania, czas zegarowy Temperatura komponentów Słabe źródła entropii Generator liczb pseudolosowych w PC (funkcja rand()) Przewidywalny, z użyciem matematycznej formuły: x k =f(x k-1 ) Powstaje problem wartości x 0 (tzw. zarodek, ang. seed) 9
Zasiewanie generatora liczb pseudolosowych W pliku nagłówowym stdlib.h zadeklarowana jest funkcja srand() o prototypie: void srand(unsigned int);...która ustala wartość początkowa generatora (seed) słowo void przed srand() oznacza, że funkcja nie zwraca żadnej wartości Przykładowe wywołanie to #include <stdlib.h> unsinged int ziarno; ziarno=(...) // wyznaczyć możliwie losową wartość ziarna srand(ziarno); Jako wartość ziarna można wziąć bieżący czas, czas czekania na wciśnięcie klawisza przez użytkownika, itp 10
Bieżący czas Do pomiaru czasu służy funkcja time() zdefiniowana w pliku nagłówkowym time.h Typowe wywołanie: long int czas; czas=time(null); Zwraca ilość sekund, jaka upłynęła od początku ery komputerowej Era komputerowa zaczeła się 1.01.1970 1 rok to ponad 30mln sekund Stąd przewiduje się zwracanie wartości większych niż UINT_MAX Prototyp: time_t time(time_t* timer); Typ time_t jest zdefiniowany (typedef) zazwyczaj jako dłuższy niż 11int
Pomiar upływu czasu (DEMO) #include <stdio.h> #include <time.h> //definiuje funkcję time() main(){ long int czas1, czas2; czas1=time(null); // ile sekund od 1.01.1970? printf("wcisnij ENTER..."); getchar(); czas2=time(null); // ile sekund od 1.01.1970? } printf("minelo %ld[s]\n", czas2-czas1); getchar(); 12
DEMO: Generowanie wartości pseudo- losowych, lepsza losowość (w3.c) #include <stdio.h> #include <conio.h> #include <stdlib.h> // definiuje funkcje rand(), srand() #include <time.h> // definiuje funkcję time() #define N 5000 int main() { int tab[n]={0}; int i; // dla jasności na początek same zera 13
DEMO: Inicjalizacja wartościami pseudo- losowymi, lepsza losowość (c.d.) srand(time(null)); // zasianie ilością sekund od 1.01.1970 for(i=n-1; i>=0; i--) { // inicjalizacja może być tez od końca tab[i]=rand()/(rand_max/100 +1); /* funkcja rand() zwraca liczbe pseudolosowa. Sprowadzam do zakresu [0;100) */ printf("wartosc na pozycji %u to: %d\n", i, tab[i]); } printf("\nczy powyzej sa wartosci losowe? \n"); getch(); } 14
Co powinienem umieć? Deklarować tablice jednowymiarowe Odwoływać się do elementów tablicy w typowych zastosowaniach Odróżniać indeks tablicy, od wartości znajdującej się pod tym indeksem tablicy Rozumieć problem uzyskiwania losowych wartości w komputerze Deklarować i wykorzystywać stałe 15