Zdeněk Janák <janak@physicsmunicz> 11 února 008 Zadání Vstupními daty bude vygenerovaný soubor s velkým množstvím náhodných čísel v intervalu 0 až N Napište program v Céčku, který tento soubor přečte a vygeneruje histogram se zadaným počtem intervalů, toto uloží do souboru Jak bude vypadat algoritmus, pokud intervaly nebudou ekvidistantní (např logaritmické měřítko)? Na čem závisí rychlost použitého algoritmu? Dodatečná úloha: Napište vlastní verzi funkce pro histogram v Octavu (jedna taková funkce tam již existuje, jmenuje se hist) a pokuste se ji napsat co nejefektivněji Porovnejte či diskutujte rychlost těchto různých implementací v závislosti na počtu vstupních dat a na počtu intervalů histogramu Generování náhodných čísel Generování náhodných čísel provádí skript randomm pro program octave, který ze zadaného rozsahu intervalu a počtu čísel vytvoří sloupcový vektor, který po vypsání na obrazovku uloží do souboru randomdat randomm 1 #!/usr/bin/octave -qf 3 # generuje soubor nahodnych cisel 5 output_precision = 10; 6 7 m = input("zadej horni mez intervalu: "); 8 m = fix(m); 9 10 n = input("zadej pocet cisel: "); 11 n = fix(n); 1 13 a = (m+1)*rand(n,1); 1 a = fix(a) 15 16 save -text "randomdat" a; 17 18 disp("cisla ulozena do souboru randomdat ");
Výstup Příklad výstupu skriptu randomm v terminálu 1 [janak@mirsam] /randomm Zadej horni mez intervalu: 500 3 Zadej pocet cisel: 100 a = 5 6 38 7 60 8 18 103 98 10 96 105 8 106 107 Cisla ulozena do souboru randomdat 108 [janak@mirsam] randomdat Příklad obsahu souboru randomdat generovaného skriptem randomm 1 # Created by Octave 169, Wed Jan 17 1:1:03 007 CET <janak@mirsam> # name: a 3 # type: matrix # rows: 100 5 # columns: 1 6 38 7 60 8 18 Příprava histogramu O rozdělení jednotlivých číselných hodnot do intervalů histogramu se stará hlavní program se zdrojem napsaným v jazyce FORTRAN v souboru histf90 Program čte soubor randomdat v předpokládaném formátu, tedy s prvními pěti řádky komentářů, které ignoruje Při prvním čtení zjistí nejvyšší hodnotu dat, která se použije jako rozsah intervalu hodnot Při druhém čtení vstupního souboru se už jednotlivé hodnoty třídí do intervalů, podle zadaného počtu a navyšují se čítače množství hodnot v jednotlivých intervalech Příslušnost do daného intervalu se zjistí jednoduše podělením zkoumané hodnoty šířkou intervalu, která je daná jako jeden díl z rozsahu hodnot při požadovaném počtu intervalů Nakonec se na obrazovku vypíše tabulka, která má v prvním sloupci střední hodnotu intervalu a v druhém počet hodnot náležících do daného intervalu Ve stejném formátu se data uloží i do souboru histdat
histf90 1! HIST -- pripravi histogram 3 program hist 5 implicit none 6 integer :: i! pomocna promenna 7 integer, parameter :: eof = -1! konec souboru 8 integer :: f! pocet intervalu 9 integer, allocatable :: h(:)! pole s histogramem 10 real :: tmp = 0, maxim = 0! nejvetsi cislo 11 real :: sirka! sirka intervalu 1 integer :: stav! stavova promenna 13 1! zadani poctu intervalu histogramu 15 print *, "Zadej pocet intervalu: " 16 read *, f 17 if (f <= 0) stop "CHYBA: Pocet intervalu musi byt vetsi nez nula!" 18 19! alokace pole pro histogram 0 allocate(h(f), stat=stav) 1 if ((stav > 0) or notallocated(h)) stop "CHYBA: Nedostatek pameti!" 3! otevreni souboru s daty open(1, file="randomdat", iostat=stav) 5 if (stav > 0) stop "CHYBA: Soubor se nepodarilo otevrit!" 6 print *, "Ctu soubor randomdat " 7 8! preskoci prvnich pet radku 9 do i = 1, 5 30 read(1,*) 31 end do 3! zjisteni maximalni hodnotu 33 do 3 read(1, fmt=*, iostat=stav) tmp 35 if (stav == eof) exit 36 if (tmp > maxim) maxim = tmp 37 end do 38 rewind(1) 39 0! preskoci prvnich pet radku 1 do i = 1, 5 read(1,*) 3 end do! rozdeleni hodnot do intervalu 5 sirka = maxim / f 6 i = 0 7 h = 0 3
8 do 9 read(1, fmt=*, iostat=stav) tmp 50 if (stav == eof) exit 51 i = int(tmp/sirka) + 1 5 if (i == (f+1)) i = f 53 h(i) = h(i) + 1 5 end do 55 56! uzavreni souboru s daty 57 close(1, iostat=stav) 58 if (stav > 0) stop "CHYBA: Soubor se nepodarilo uzavrit!" 59 60! otevreni souboru s vysledkem 61 open(, file="histdat", iostat=stav) 6 if (stav > 0) stop "CHYBA: Nepodarilo se otevrit soubor!" 63 6! zapsani vysledku na obrazovku a do souboru 65 do i = 1, f 66 print *, sirka/0+(i-1)*sirka, h(i) 67 write(, fmt=*, iostat=stav) sirka/0+(i-1)*sirka, h(i) 68 if (stav > 0) stop "CHYBA: Nepodarilo se zapsat do souboru!" 69 end do 70 endfile(, iostat=stav) 71 if (stav > 0) stop "CHYBA: Nepodarilo se zapsat do souboru!" 7 73! uzavreni souboru s vysledkem 7 close(, iostat=stav) 75 if (stav > 0) stop "CHYBA: Soubor se nepodarilo uzavrit!" 76 print *, " zapsan do souboru histdat " 77 78! uvolneni pole histogramu 79 deallocate(h, stat=stav) 80 if (stav > 0) stop "CHYBA: Nepodarilo se uvolnit pamet!" 81 8 end program hist Výstup Příklad výstupu hlavního programu na terminál 1 [janak@mirsam] ifort -o hist histf90 && /hist Zadej pocet intervalu: 3 10 Ctu soubor randomdat 5 0000 8 6 760001 9 7 110000 8 1 3630000 7 13 11000 1
1 598000 10 15 zapsan do souboru histdat 16 [janak@mirsam] Příklad obsahu souboru histdat 1 80000 9 739999 11 3 10000 10 8 370000 1 9 16000 11 10 71000 10 histdat Graf histogramu Graf s histogramem zobrazuje skript histgp pro gnuplot, který vykresluje data ze souboru histdat histgp 1 #!/usr/bin/gnuplot # vykresli histogram na obrazovku 3 set enc iso_8859_ set nokey 5 set title "" 6 set xlabel "Hodnota" 7 set ylabel "Počet" 8 set style fill solid 08 border -1 9 plot [] [0:] "histdat" with boxes 10 pause -1 "Ukonci stiskem <enter> " Výstup skriptu histgp v terminálu 1 [janak@mirsam] /histgp Ukonci stiskem <enter> 3 [janak@mirsam] Výstup Graf histogramu Samotný graf s histogramem je zobrazen na obrázku 5
1 1 10 8 Počet 6 0 0 50 100 150 00 50 300 350 00 50 500 Hodnota Diskuze na závěr Je možné, že v kódu nejsou ošetřeny všechny chybové stavy, které mohou při běhu programu nastat Při neekvidistantních intervalech by asi bylo třeba složitěji určovat příslušnost jednotlivých hodnot do odpovídajících intervalů Rychlost programu by se asi výrazně nezměnila, protože ta je lineárně úměrná počtů prvků množiny Dokumentace Dokumentace je napsaná ve formátu L A T E X ε, pomocí písma Bera Citace zdrojových textů obstarává balík listings Přílohy Archiv histtgz obsahuje jednak samotné skripty generující a zobrazující data a zdrojový kód hlavního programu, tak v adresáři doc/ soubory potřebné k vytvoření dokumentace README stručný návod k použití randomm skript v octave pro generování náhodných čísel histf90 zdrojový kód programu napsaný ve FORTRANu histgp skript pro gnuplot vykreslující graf s histogramem histogramtex zdrojový text dokumentace ve formátu L A T E X ε 6