+ All Categories
Home > Documents > 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 =...

1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 =...

Date post: 29-Sep-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
64
1 1. Zobrazení informací v počítači Číselné soustavy Převod mezi dvěma soustavami odpovídá jednoznačnému zobrazení mezi dvěma množinami. 1. množina – množina čísel 2. množina – množina cifer Příklad: číslo 123 je v desítkové soustavě 1 stovka, 2 desítky a tři jednotky, v šedesátkové dvě šedesátky a tři jednotky. (2 minuty, 3 vteřiny) Desítková soustava: 256 10 = 2*10 2 + 5*10 1 + 6*10 0 Číslo vyjadřujeme pomocí mocnin 10 a cifer 0,1..9, k zápisu použijeme jen zhuštěnou formu (tuččinitelé) Analogicky ve dvojkové soustavě užíváme mocnin dvou a cifer 0,1. Obecně hovoříme o polyadických soustavách o základu z. a n z n + a n-1 z n-1 + … a 0 z 0 Pro desetinná (racionální čísla) můžeme pokračovat dále: a n z n + a n-1 z n-1 + … a 0z 0 + a -1 z -1 + a -2 z -2 + … a i ˛ {0, 1, … z-1} Dvojková soustava: Postup při převodu z desítkové do dvojkové soustavy: Číslo postupně dělíme dvěma a zapisujeme zbytky, dokud není celočíselný podíl roven nule. Zbytky pak opíšeme v opačném pořadí. Dělení: 13 : 2 = 6 : 2 = 3 : 2 = 1 : 2 = 0 Zbytky:1 0 1 1 Výsledek: 13 10 = 1101 2 (Stejný postup lze použít i při převodu do jiných soustav) Algoritmus vychází z toho, že opakovaným dělením zjišťujeme, jaké mocniny základu jsou ve výchozím čísle obsaženy. Postup při převodu z dvojkové do desítkové soustavy Příklad: 101 2 =1*2 2 +0*2 1 +1*2 0 U delších čísel by byl postup s výpočtem mocnin neefektivní, proto používáme Hornerovo schéma pro výpočet hodnoty polynomu: A n x n + a n-1 x n-1 +a n-2 x n-2 + …a 1 x +a 0 =(…((a n x+a n-1 )x + a n-2 )x + …a 1 )x+a 0 Šestnáctková soustava Protože zápisy v dvojkové soustavě jsou dlouhé, používá se prakticky soustava šestnáctková, která umožňuje jejich zhuštění. Obě soustavy se snadno vzájemně převádějí, viz. dále. Tato soustava má základ 16 a používá tedy 16 cifer, rp. naků pro cifry. 0,1, …9 a dále písmena pro dvouciferná čísla desítkové soustavy: A 10 B 11 C 12 D 13 E 14 F 15 Převody mezi dvojkovou a hexadecimální soustavou Jeden znak hexadecimální soustavy odpovídá čtyřem znakům binární soustavy. (Např A 16 = 10 10 =1010 2 ) Číslo ve dvojkové soustavě rozdělíme po čtveřicích cifer odzadu a každou čtveřici přepíšeme do šestnáctkové soustavy a naopak. Příklad: 3 6 D 16 =11 0110 1101 2
Transcript
Page 1: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

1

1. Zobrazení informací v počítači

Číselné soustavy Převod mezi dvěma soustavami odpovídá jednoznačnému zobrazení mezi dvěma množinami. 1. množina – množina čísel 2. množina – množina cifer Příklad: číslo 123 je v desítkové soustavě 1 stovka, 2 desítky a tři jednotky, v šedesátkové dvě šedesátky a tři jednotky. (2 minuty, 3 vteřiny) Desítková soustava: 25610 = 2*102 + 5*101 + 6*100

Číslo vyjadřujeme pomocí mocnin 10 a cifer 0,1..9, k zápisu použijeme jen zhuštěnou formu (tuční činitelé) Analogicky ve dvojkové soustavě užíváme mocnin dvou a cifer 0,1. Obecně hovoříme o polyadických soustavách o základu z. anzn + an-1zn-1 + … a0z0

Pro desetinná (racionální čísla) můžeme pokračovat dále: anzn + an-1zn-1 + … a0z

0 + a-1z-1 + a-2z-2 + … ai ∈ {0, 1, … z-1} Dvojková soustava: Postup při převodu z desítkové do dvojkové soustavy: Číslo postupně dělíme dvěma a zapisujeme zbytky, dokud není celočíselný podíl roven nule. Zbytky pak opíšeme v opačném pořadí. Dělení: 13 : 2 = 6 : 2 = 3 : 2 = 1 : 2 = 0 Zbytky:1 0 1 1 Výsledek: 1310 = 11012 (Stejný postup lze použít i při převodu do jiných soustav) Algoritmus vychází z toho, že opakovaným dělením zjišťujeme, jaké mocniny základu jsou ve výchozím čísle obsaženy. Postup při převodu z dvojkové do desítkové soustavy Příklad: 1012 =1*22 +0*21 +1*20

U delších čísel by byl postup s výpočtem mocnin neefektivní, proto používáme Hornerovo schéma pro výpočet hodnoty polynomu: Anxn + an-1xn-1 +an-2xn-2 + …a1x +a0 =(…((anx+an-1)x + an-2)x + …a1)x+a0

Šestnáctková soustava Protože zápisy v dvojkové soustavě jsou dlouhé, používá se prakticky soustava šestnáctková, která umožňuje jejich zhuštění. Obě soustavy se snadno vzájemně převádějí, viz. dále. Tato soustava má základ 16 a používá tedy 16 cifer, rp. naků pro cifry. 0,1, …9 a dále písmena pro dvouciferná čísla desítkové soustavy: A 10 B 11 C 12 D 13 E 14 F 15 Převody mezi dvojkovou a hexadecimální soustavou Jeden znak hexadecimální soustavy odpovídá čtyřem znakům binární soustavy. (Např A16 = 1010 =10102) Číslo ve dvojkové soustavě rozdělíme po čtveřicích cifer odzadu a každou čtveřici přepíšeme do šestnáctkové soustavy a naopak. Příklad: 3 6 D16 =11 0110 11012

Page 2: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

2

Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika reálných čísel vždy nepřesná, na rozdíl od práce s celočíselnými typy.

Aritmetické operace v jiných soustavách Analogicky desítkové – příklad písemné sčítání: 3268 1258

4538 (5+6=11=8+3, takže trojku zapíšeme a 8 převedeme jako 1 (81) do vyššího řádu

Zobrazení celých čísel Celé kladné číslo se většinou ukládá do čtyř B převedené do dvojkové soustavy. (16bitové procesory používaly pouze 2B.) Např.: 12310 = 11110112 se uloží takto: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1

Záporná čísla se zobrazují pomocí dvojkového doplňkového kódu; jeho kladná podoba se převede do binární soustavy, provede se inverze všech bitů (0-1,1-0) a k výsledku se přičte jednička. Příklad pro zobrazení čísla do dvou bitů (z praktických důvodů):

00 0 -1: 01 inverze 10 +1 =11 01 +1 -2: 10 01+1=10 10 -2 11 -1

Podobně se kódují větší celá čísla, jiný způsob ukládání se užívá u reálných čísel, kde se ukládá do skupin bytů nejprve normalizovaná mantisa (z intervalu<0,1; 1), pak exponent. Př.: 123,4 =0,1234 *103

mantisa: 0,1234; exponent: 3

Zobrazení znaků Dosud nejznámější je osmibitový kód ASCII . (Každý znak se ukládá do 1 B) Prvních 128 znaků je všude stejných, druhých 128 se liší pro různé druhy abeced (národní abecedy) a jejich kódování (Např. Windows užívají kódovou stránku 852, některé starší programy mohou pracovat s poněkud odlišným kódem Kamenických apod.) Příklad: Znak pořadové číslo v tabulce ASCII Dvojková reprezentace @ 64 01000000 A 65 01000001 ~ 126 01111110 Stisknete-li současně klávesu Alt a pořadové číslo v tabulce (na numerické klávesnici), napíše se příslušný znak. Všimněte si, že od znaku 128 záleží také na volbě klávesnice. V současnosti nabývá na významu Unicode, kde se znaky zobrazují do 2B a vejdou se tedy všechny potřebné znaky národních abeced jednoznačně. Kromě toho existuje kód UTF 8 s proměnnou délkou 1-3 B.

Page 3: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

3

Cvičení Naprogramujte následující převody: 1. Dvojková soustava -> desítková soustava (použijte Hornerovo schéma) 2. Desítková soustava-> soustava o základu z<=9 3. Desítková soustava -> šestnáctková soustava 4. Šestnáctková soustava -> dvojková soustava, každé hexadecimální cifře přiřaďte odpovídající čtveřici

binárních cifer.

Řešení: 1. procedure TForm1.BitBtn2Click(Sender: TObject); {prevod ze soustavy o yakladu z, Hornerovo schema} var vys,z,i,k:integer;s,p:string; begin z:=strtoint(edit2.Text); s:=edit1.Text; k:=length(s); vys:=0; for i:=1 to k do begin vys:=strtoint(s[i])+vys*z; end; showmessage(inttostr(vys)); end; 2. function prevod(x,z:integer):string; {prevod do soustavy se zakladem mensim nez 10} var s:string;p:integer; begin s:=''; repeat p:= x mod z; s:= inttostr(p)+s; x:= x div z; until x=0; prevod:=s; end; 3. function prevodhex(x:integer):string; {prevod do sestnactkove soustavy} var s:string;p:integer; begin s:=''; repeat p:= x mod 16; if p<10 then s:= inttostr(p)+s else case p of 10:s:='A'+s; 11:s:='B'+s; 12:s:='C'+s; 13:s:='D'+s; 14:s:='E'+s; 15:s:='F'+s; end; x:= x div 16; until x=0; prevodhex:=s; end; 4. převodní tabulka:

Page 4: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

4

type binhex=record hex:string; bin:string; end; var kod:array[0..15]of binhex; procedure TForm1.FormCreate(Sender: TObject); {vytvoreni prevodni tabulky} var i:0..15; begin for i:=0 to 15 do begin case length(prevod(i,2)) of 1: kod[i].bin:='000'+prevod(i,2); 2: kod[i].bin:='00'+prevod(i,2); 3: kod[i].bin:='0'+prevod(i,2); 4:kod[i].bin:=prevod(i,2); end; kod[i].hex:=prevodhex(i); end; end; procedure TForm1.Label8Click(Sender: TObject); {prevod 16koveho cisla z editu na dvojkove cislo pomoci převodní tabulky} var s,vys,pom:string;i,j:integer; begin s:= edit6.Text; vys:=''; for i:=1 to length(s) do begin pom:=s[i]; j:=0; while kod[j].hex<>pom do inc(j); vys:=vys+kod[j].bin; end; showmessage(vys); end;

2. Syntaxe programovacích jazyků, syntaktický analyzátor Syntaxe =souhrn gramatických pravidel (Jak ze slov dělat věty) Sémantika = význam vět Syntakticky správná věta může být sémanticky nesmyslná. Gramatika přirozených jazyků je příliš složitá a nejednoznačná, navíc má potenciálně neomezený slovník – pro komunikaci člověka s počítačem se vytvářejí jazyky umělé s přesně definovanou syntaxí.

Definice Gramatika = (N, Σ, P ,S) N konečná množina neterminálů – symboly, které se dále definují (Věta, podmět, program, podmíněný příkaz…) Σ konečná množina terminálů („slovník“ – abeceda jazyka, může obsahovat i víceznakové symboly – if

apod.) Σ∩N=∅ – terminály a neterminály jsou disjunktní S kořen gramatiky – neterminál, od kterého se začíná odvozovat (věta, program) P množina přepisovacích pravidel : Konečnou posloupnost neterminálů a terminálů….vyjádři jako….jinou konečnou posloupnost neterminálů a terminálů Podle typů pravidel rozlišujeme více druhů gramatik: Chomského hierarchie:

Page 5: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

5

Regulární, bezkontextové, kontextové, bez omezení (Přirozený jazyk) Bezkontextové gramatiky CFG mají velký význam při konstrukci programovacích jazyků, pravidla vypadají tak, že nalevo stojí jediný neterminál, napravo konečná posloupnost terminálních a neterminálních symbolů. Derivace – odvození – začíná kořenem gramatiky a končí posloupností terminálů Věta jazyka – takto odvozená posloupnost terminálů Jazyk generovaný gramatikou – množina všech vět. Díky tomu, že jazykové konstrukce programovacích jazyků jsou přesně definované gramatickými pravidly, může syntaktickou správnost kontrolovat překladač.

Formalismy zápisů pravidel BNF (Backus Nauerova Forma) Syntaktické diagramy Terminál X (bez <>) Neterminál<X> <X>::=<X1>|<X2>|<X3> alternativní možnost řetězec <X>::=<X1><X2><X3> <X>::={<Y>} symbol ve složených závorkách se může vyskytovat libovolněkrát (také vůbec ne) Příklad 1: identifikátor v Pascalu (původní nejjednodušší definice) = posloupnost písmen a číslic, začínající písmenem.. BNF: <identifikátor>::=<písmeno>|<identifikátor><písmeno>|<identifikátor><číslice> <písmeno>::=A|B|………….|z <číslice>::=0|1|2……|9 SD: Písmeno

X1

X2

X3

X1 X2 X3

X

X

Y

písmeno

identifikátor

identifikátor písmeno

číslice

A

z

Page 6: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

6

Číslice Syntaktický analyzátor – program, který pozná, zda je nějaká posloupnost symbolů správně vytvořená. Předpokládáme, že věta, kterou budeme analyzovat je v řádku textového souboru, terminály jsou jednotlivé znaky. Proměnná ch typu znak reprezentuje načítaný symbol, načtení znaku – read(f,ch); Velká písmena označují neterminály –v programu rekurzivní procedury, malá písmena jsou znaky –terminály. Postup: pomocí syntaktických diagramů odvodíme vývojový diagram a přepíšeme ho do programovacího jazyka. Příklad 2: 1. Uveďte příklad derivace věty v dále popsaném jazyce. 2. Napište syntaktický analyzátor, který rozhodne, zda posloupnost znaků v editačním políčku je věta dané gramatiky. G={{A,B,C};{x,+,(,)},A} Pravidla: A::=x|(B) B::=AC C::={+A} Syntaktické diagramy: A B C Postupným nahrazováním: A Příklady generovaných vět: x, (x), (x+x),((x))….

Vstup tedy bereme z textového souboru, kde můžeme snadno načítat jednotlivé znaky procedurou read(f,znak) procedure TForm1.Button2Click(Sender: TObject); var ch:char; er:boolean; f:textfile; procedure A; begin er:=false; if ch='x' then read(f,ch) else if ch='(' then begin read(f,ch);

0

9

A

+ A

( )

x

(

x

B )

A C

A +

Page 7: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

7

A; while ch='+' do begin read(f,ch);A; end; if ch=')' then read(f,ch) else er:=true end else er:=true; end; begin assignfile(f,'File1.txt'); listbox1.Items.LoadFromFile('File1.txt'); reset(f); read(f,ch); A; if not er then showmessage('BERU') ELSE showmessage('neberu'); end;

Příklady: 1. Naprogramujte generátor náhodných řetězců náhodné délky. 2. Naprogramujte generátor náhodných řetězců náhodné délky, bude obsahovat písmena malé a velké abecedy

bez diakritiky a číslice. 3. Naprogramujte nerekurzívní logickou funkci, která pozná pascalský identifikátor a vyzkoušejte ji na

řetězcích 1,2. (Např. můžete geberovat řetězce do jednoho listboxu a identifikátory pak přesouvat do druhého.)

Řešení 1. procedure TForm1.Button4Click(Sender: TObject); var i,pocet,delka,j,x:integer;s:string; begin pocet:=random(20)+1; delka:=random(20)+1; for i:=1 to pocet do {generovani slov} begin s:=''; for j:=1 to delka do begin x:=random(207)+48; s:=s+chr(x); end; listbox1.items.add(s); end; end;

2. procedure TForm1.Button1Click(Sender: TObject); {program generuje nahodne znaky a z nich bere potrebne, efektivnejsi by bylo nejprve si rozsahy zjistit} var i,pocet,delka,j,x:integer;s:string; begin pocet:=random(20)+1; delka:=random(20)+1; for i:=1 to pocet do {generovani slov}

Page 8: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

8

begin s:=''; for j:=1 to delka do begin repeat x:=random(207)+48;{bez ridicich znaku} until (chr(x) in ['A'..'Z']) or (chr(x) in ['a'..'z'])or (chr(x) in ['0'..'9']); s:=s+chr(x); end; listbox1.items.add(s); end; end; 3. procedure TForm1.Button3Click(Sender: TObject); function id(s:string):boolean; var i:integer; begin if (s[1] in ['A'..'Z'])or (s[1] in ['a'..'z'])then begin i:=2; while (i<=length(s)) and ((s[i] in ['A'..'Z'])or (s[i] in ['a'..'z'])or(s[i] in ['0'..'9']))do inc(i); id:=(i>length(s)) end else id:=false; end; var i:integer; begin for i:=0 to listbox1.items.count-1 do if id(listbox1.items[i]) then listbox2.items.add(listbox1.items[i]); end;

3. Úvod do numerických metod

Vyhodnocování výrazů A*B/C může být: a*b div c

a*b / c – může způsobit přetečení i když c je dost velké, aby byl výsledek rozumný (řešení a / c * b ) výsledek může být nula pokud a* b je strojová nula (číslo menší než nejmenší zobrazitelné číslo) i když c je hodně malé.

Problémy s přetečením mohou nastat i když např. Var a,b:integer;x:real X:=(a*b)/3 – pokud a*b přeteče, výsledek nemusí být správný.

Test na rovnost Pozor u rovnosti reálných čísel (viz. zobrazení čísel v počítači), spolehlivější je porovnání provést pouze s určitou přesností. Function rovnost(a,b,eps:real); Begin rovnost=abs(a-b)<eps End Výpočet hodnoty polynomu (Hornerovo schéma) Přímý výpočet by byl jednak časově náročný vzhledem k umocňování, jednak může být neúspěšné z důvodu přetčení.

Page 9: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

9

Pn(x)=Anxn + an-1xn-1 +an-2xn-2 + …a1x +a0 =(…((anx+an-1)x + an-2)x + …a1)x+a0 function horner(x:real;a:pole;n:integer):real; var i:integer;s:real; begin s:=0; {od nejvyssi mocniny} for i:=0 to n do s:=s*x+a[i]; horner:=s; end;

Numerické integrování Výpočet obsahu plochy pod křivkou:

Obdélníkové pravidlo Přesně: ∫ −=b

a

aFbFdxxf )()()(

A s B P=(b-a)*f((a+b)/2) Lichoběžníkové pravidlo: P=[f(a)+f(b)]*(b-a)/2

Když počítáme všechny lichoběžníky, vlastně můžeme vytknout délku dílku a počítat pouze funkční hodnoty ve středech dílků. function lichob(a,b:real;n:integer):real;

var x,h,s:real;i:integer; begin h:=(b-a)/n;

s:=(f(a)+f(b))/2; x:=a+h; for i:= 1 to n-1 do begin s:=s+f(x);x:=x+h; end; s:=s*h; lichob:=s; end;

Řešení rovnic s jednou neznámou F(x)=0

Page 10: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

10

Př.. Sin(x)-exp(x)+x3=0 analyticky řešit neumíme. Numerický postup: 1. Separace kořenů – vyhledání intervalů, ve kterých existuje jediný kořen 2. Zpřesnění kořenů – kořeny vyhledáme s určitou požadovanou přesností. Věta: Nechť je f fce spojitá na intervalu <a,b>., f(a)*f(b)<0 Pak má daná rovnice v intervalu alespoň jeden kořen. Pokud je funkce monotónní (1.derivace nemění znaménko), je kořen právě jeden. Metoda půlení intervalu 1. Střed intervalu: (a+b)/2 2. f(s) 3. Pokud f(a)*f(s)<0. Křen náleží <a,s> a v tomto

A s B Intervalu budeme pokračovat, jinak zvolíme druhý interval <s,b> Opakujeme, dokud se |f(s)| neblíží nule podle našich požadavků. program pulint; {$F+} {tato direktiva umoznuje vzdalene volani prcedur fce muze byt parametr jine fce} type ufce=function(x:real):real; function pul(a,b,eps:real;f:ufce):real; var s:real; begin repeat s:=(a+b)/2; if f(s)*f(a)<0 then b:=s else a:=s; until abs(f(s))<eps; pul:=s; end; function f1(x:real):real; begin f1:=x*x*x-8; end; var a1,b1,e1:real; begin readln(a1,b1,e1); writeln(pul(a1,b1,e1,f1):6:2); readln; end.

Metoda sečen

01

01

1

1 )()()(xx

xfxfxxxfytg

−−

=−

−=α

Rovnice sečny:

)()()(

)( 001

011 xx

xxxfxfxfy −

−−

=−

Průsečík s osou x: Y=0

)()()(

)( 1201

011 xx

xxxfxfxf −

−−

=−

Page 11: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

11

)(*)()( 1

01

0112 xf

xfxfxxxx

−−

−=

Obecně:

)(*)()( 1

11 n

nn

nnnn xf

xfxfxxxx

−+ −

−−=

function secny(f:userfce;a,b,eps:real):real; var n,s,p:real; begin p:=a;s:=b; repeat n:=p-(p-s)/(f(p)-f(s))*f(p); s:=p;p:=n; until abs(f(n))<eps; secny:=n; end;

Cvičení: 1. Vymyslete si způsob jak zadat vstupní hodnoty a vyzkoušejte si uvedené algoritmy. 2. Hodnoty některých funkcí se dají vypočítat pomocí součtu nekonečných řad. (Taylorovy, MacLaurinovy rozvoje) Naprogramujte výpočet pro exponenciální funkci a funkci sinus, nepoužívejte přitom oddělený výpočet mocnin a faktoriálu, protože by brzy došlo k přetečení. V zásadě půjde o to, že v každém kroku vypočítáme člen, který se bude k předchozí řadě přičítat a výpočet ukončíme, když bude dostatečně malý. (Uživatelsky omezíme přesnost)

...!3!2!1

32

+++=xxxe x

...!7!5!3

sin753

+−+−=xxxxx

Řešení: 2. function expx(X,eps:Real):real; {eps-presnost, clen-nasledujici clen rozvoje} var clen,s:real;n:integer; begin s:=1; clen:=1; n:=1; while clen>eps do begin clen:=clen*x/n; n:=n+1; s:=s+clen; end; result:=s; end; function sinxx(x,eps:real):real; {eps-presnost, clen-nasledujici clen rozvoje} var clen,s:real;n:integer; begin s:=0; clen:=x; n:=1; while abs(clen)>eps do begin s:=s+clen; n:=n+2; clen:=-clen*x*x/((n)*(n-1)); end; result:=s; end;

Page 12: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

12

4. Řešení soustavy lineárních rovnic Gaussovou eliminační metodou. Mějme soustavu n lineárních rovnic o n neznámých:

11212111 bxaxaxa nn =++ K

22222121 bxaxaxa nn =++ K …

nnnnnn bxaxaxa =++ K2211

Pokud existuje právě jendo řešení ( nxxx K,, 21 ), říkáme, že je soustava regulární. Pokud řešení nemá, nebo jich je nekonečně mnoho, nazýváme soustavu singulární. Například pro n=2

123 21 =+ xx

221 =− xx má soustava právě jeno řešení (1,-1) Singulární soustava 123 21 =+ xx

246 21 =+ xx má řešení nekonečně mnoho, kdyby na pravé straně druhé rovnice nebyla dvojka, soustava by řešení neměla. Eliminační metody převádějí soustavu na přijatelnější tvar, přitom zachovávají množinu řešení původní rovnice. Takovým soustavám říkáme ekvivalentní. (Ekvivalentní jsou také úpravy, které nemění množinu řešení výchozí rovnice) Jedním ze zmiňovaných přijatelnějších tvarů je tvar trojúhelníkový:

11212111 bxaxaxa nn =++ K

22222 bxaxa nn =+K

nnnn bxa = je to tedy soustava, kde všechny koeficienty pod hlavní diagonálou jsou nulové. Z poslední rovnice je snadné vypočítat nx , to pak dosadit do rovnice předposlední atd. Ekvivalentní úpravy:

• Záměna dvou rovnic soustavy (budeme potřebovat v i-té rovnici mít neznámou ix ) • Vynásobení některé rovnice nenulovou konstantou • Přičtení násobku jedné rovnice ke druhé (eliminace proměnné)

Gaussova eliminační metoda: 1. soustavu přecedem na trojúhelníkový tvar 2. zpětný chod – výpočet hodnot neznámých. Místo celých rovnic budeme upravovat jen matice jejich koeficientů.

11212111 bxaxaxa nn =++ K

22222121 bxaxaxa nn =++ K

Abychom z druhé rovnice eliminovali 121xa , musíme k ní přičíst první rovnici vynásobenou koeficientem

1121 / aa−

Obecně i-tou rovnici: 111 / aai− Převod na trojúhelníkový tvar: for k:=1 to n-1 do {eliminace xk} for i:=k+1 to n do {uprava i-te rovnice} begin for j:=k+1 to n do {pozor: abychom skutečně získali pod hlavní diagonálou nuly, bylo by třeba začít cyklus od j=k. Jakmile se ale vynuluje aik, od dalších členů už by se nic neodčítalo. Pokud bychom tedy chtěli mít pod hlavní diagonálou nuly (třeba aby se dala upravená soustava vypsat, ve skutečnosti na těchto členech nezáleží), je nutno si nejprve aik zapamatovat do jiné proměnné a tu pak místo aijk použít.} aij:=aij-aik/akk*akj; {uprava leve strany} bi:=bi-aik/akk*bk {uprava prave strany} end ;

Page 13: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

13

Zpětný chod : Poznámka: po skončení všech úprav bude platit, že xk=bk. for k:=n downto 1 do begin for i:= k+1 to n do bk:=bk-aki*bi; bk:=bk/akk; end; Možný problém: Dělení nulou: pokud koeficient proměnné, kterou odstraňujeme z dalších rovnic, pokusíme se mezi následujícími rovnicemi najít takovou, která má tentokoeficient nenulový a rovnice vyměníme. Pokud se nám to nepodaří, je soustava singulární a mohou nastat dva případy. 0=0 nekonečně řešení 0=bk<>0 žádné řešení Cvičení: Naprogramujte řešení n lineárních rovnic o n neznámých. Koeficienty lze zadávat např. do komponenty Stringgrid. Řešení soustava=record n:integer; lev:array[1..6,1..6]of real;{koeficienty leve strany} prav:array[1..6]of real;{prava strana} end; var Form1: TForm1; a:soustava; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var i:integer; begin a.n:=spinedit1.Value; stringgrid1.ColCount:=a.n+2; stringgrid1.RowCount:=a.n+1; stringgrid1.cells[0,0]:='rovnice'; for i:=1 to a.n do begin stringgrid1.Cells[0,i]:=inttostr(i); stringgrid1.Cells[i,0]:='koef u x'+inttostr(a.n-i+1); end; stringgrid1.Cells[a.n+1,0]:='prava strana'; stringgrid1.Visible:=true; end; procedure vymen(var x,y:real); var pom:real; begin pom:=x; x:=y; y:=pom; end; procedure TForm1.Button2Click(Sender: TObject); {reseni soustavy linearnich rovnic Gaussovou metodou; koeficienty neznamych jsou v matici a.lev, koeficienty prave strany v poli a.prav U regularni soustavy jsou vysledky v poli b, u singularni se resi, zda ma nekonecne nebo zadne reseni} var p,i,j,k,m:integer;sing:boolean; begin {nacteni koeficientu}

Page 14: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

14

for i:=1 to a.n do begin for j:=1 to a.n do a.lev[i,j]:=strtofloat(stringgrid1.cells[j,i]); a.prav[i]:=strtofloat(stringgrid1.cells[a.n+1,i]); end; sing:=false; {predp., ze soustava ma reseni} k:=1; while not sing and (k<=a.n) do {eleminujem xk} begin if a.lev[k,k]=0 then {upravujeme soustavu, kde jsou na hlavni diagonale nuly} begin m:=k+1; while (a.lev[m,k]=0) and (m<a.n) do {hledam a[m,k]<>0} m:=m+1; if a.lev[m,k]=0 then begin sing:=true; {neuspech jednoznacneho reseni} p:=k; {zapamatujeme si, kde je problem} end else begin {vymena m teho a k-teho radku} for i:=k to a.n do vymen(a.lev[k,i],a.lev[m,i]); vymen(a.prav[k],a.prav[m]); end; end; if not sing then {a[k,k]<>0, muzeme eliminovat xk} for i:=k+1 to a.n do {uprava i-te rovnice} begin for j:=k+1 to a.n do {uprava koef. pri xj} a.lev[i,j]:=a.lev[i,j]-a.lev[i,k]/a.lev[k,k]*a.lev[k,j]; a.prav[i]:=a.prav[i]-a.lev[i,k]/a.lev[k,k]*a.prav[k]; end; inc(k); end; if not sing {regulerni soustava je prevedena na trojuh. tvar -zpetny chod} then for k:=a.n downto 1 do begin for i:= k+1 to a.n do a.prav[k]:=a.prav[k]-a.lev[k,i]*a.prav[i]; a.prav[k]:=a.prav[k]/a.lev[k,k]; listbox1.items.add ('x'+floattostr(k)+'='+floattostr(a.prav[k])); end; if sing then begin showmessage('singularni soustava'); if a.prav[p]=0 then showmessage('nekonecne reseni') else showmessage('nema reseni'); end; end; end.

5. Statistika, modelování náhodných dějů

Statistika Statistický soubor – množina všech objektů výzkumu Prvky souboru – prvky této množiny Rozsah souboru – počet prvků Stat. Znak – sledovaná vlastnost prvků souboru – x Jednotlivé údaje oznaku – hodnoty znaku x1 x2 …xk.(př. počet dětí v jednotlivých rodinách) Četnost hodnoty znaku xj – počet prvků, které vykazují stejnou hodnotu znaku – nj

Page 15: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

15

(počet rodin s 5 dětmi…)

Relativní četnost -nn j

jν= prakticky v %

∑=

=k

jj nn

1

∑=

=k

jj

1

Tabulka rozdělení četnosti j xj nj Čárkovací metoda: Hodnoty znaku napíšeme pod sebe a jak procházíme prvky souboru, děláme čárky do příslušných řádků While not eof(f) do begin read(f,x),inc(počet[x]) –je třeba, aby x bylo ordinální. Jinak např. použití záznamu: Prvek=record znak:typprvku; Počet: integer; Hotov:boolean; End; Soubor procházíme a zpracované prvky zaslepujume (hotov=true) Histogram – sloupcový diagram, sloupce – obdélníčky a obsahy úměrnými četnostem

Aritmetický průměr ∑=

=n

jjj xn

nx

1

1

Geometrický průměr nnxxxx ...21=

Harmonický průměr

nxx

nx1...1

1

=

Modus – hodnota znaku s max.četností – maximum tabulky četností Medián – hodnota prostředního znaku v setříděné tabulce četností (asi stejný počet prvků je menších jako větších oproti mediánu) Pro lichý počet prvků má index (n+1) div 2, pro sudý počet se vypočítá jako průměr „prostředních“ prvků

2

122

++

nana

Průměrná odchylka ( ) ( )∑∑ −=−= xxnn

xxn

d iii11

Rozptyl ( ) ( )22

1

2 11 ∑∑ −=−==

xxnn

xxn

s ii

n

iix

For i:=1 to n do s:=s+sqr(x[i]-prumer); s:=s/n

Směrodatná odchylka 2xss =

Pro zjištění závislosti dvou znaků:

Koeficient korelace r=21ss

k ( )2

11 ∑ −= xxn

s i ( )21

1 ∑ −= yyn

s i

( )( )yyxxn

k ii −−= ∑1

Pokud r se blíží k 1, je mezi znaky x a y velká závislost, pokud k 0, malá. Hodnoty kolem -1 naznačují nepřímou úměrnost.

Page 16: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

16

Modelování náhodných dějů Generátor náhodných čísel Pascal: Randomize – inicializace generátoru (používá obvykle systémový čas) Random Random(10) Random(10)+11 –generuje celá čísla od 11 do 20 Excel Náhčíslo(), Celá.část(náhčíslo()*100) –náhodná celá čísla od 0 do 99 nebo randbetween(10) jako pascalské random(10) Algoritmy Většinou se vypočítá následující číslo z předchozího, generovaná posloupnost musí vykazovat charakteristiky požadované od náhodných čísel. Př. yk+1=(A yk+B) mod C A, B, C – konstanty, C udává periodu opakování posloupnosti. Příklad: A =17 (prvočíslo), B = 1, C je nějaká mocnina 2. Polem: y[i+1]:=(17 y[i] + 1] mod 4 Programování vzájemně se vylučujících jevů Pokud mají pravděpodobnost p, 1-p: If random <p Then výskyt 1.jevu Else výskyt druhého jevu

Cvičení: 1. Načtěte z textového souboru data, (celá čísla 0-9), setřiďte ho a vypočítejte jeho statistické charakteristiky. Zobrazte příslušný histogram. 2. Můžete vyzkoušet vlastní algoritmus generování náhodných čísel

Řešení 1. var Form1: TForm1; cet:array[0..9]of integer; implementation uses Unit2; {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin listbox1.items.loadfromfile('data.txt'); listbox2.items.loadfromfile('data.txt'); end; procedure TForm1.Button2Click(Sender: TObject); var a:array[1..1000]of integer; n,i,mods:integer; pr,roz,med,smch:real; begin n:=listbox1.items.count; pr:=0; for i:=0 to 9 do cet[i]:=0; for i:=1 to n do begin a[i]:=strtoint(listbox2.items[i-1]); inc(cet[a[i]]); pr:= pr+a[i]; end; pr:=pr/n;

Page 17: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

17

if odd(n) then med:=a[(n+1) div 2 ] else med:=(a[n div 2]+a[n div 2+1])/2; mods:=0; for i:=0 to 9 do if cet[i]>mods then mods:=i; roz:=0; for i:=1 to n do roz:=roz+sqr(a[i]-pr); roz:=roz/n; smch:=sqrt(roz); listbox3.items.add('rozsah '+inttostr(n)); listbox3.items.add('prumer '+floattostr(pr)); listbox3.items.add('median '+floattostr(med)); listbox3.items.add('znak jeho cetnost'); for i:=0 to 9 do listbox3.items.add(inttostr(i)+' '+inttostr(cet[i])); listbox3.items.add('modus '+inttostr(mods)); listbox3.items.add('rozptyl '+floattostr(roz)); listbox3.items.add('smer.odch '+floattostr(smch)); end; procedure TForm1.Button3Click(Sender: TObject); var i:integer; begin form2.show; form2.image1.canvas.brush.color:=clsilver; for i:=0 to 9 do form2.image1.canvas.rectangle(30*i,200-cet[i]*30,i*30+30,200); end; 2. procedure TForm1.BitBtn1Click(Sender: TObject); const max=1000; var i,n,a,b,c:integer; d:array[1..max]of integer; begin listbox1.Clear; d[1]:=spinedit5.value; n:=spinedit1.Value; a:=spinedit2.Value; b:=spinedit3.Value; c:=spinedit4.Value; for i:=1 to n-1 do begin d[i+1]:=(a*d[i]+b)mod c; listbox1.items.Add(inttostr(d[i+1])) end; end;

6. Multitasking a Delphi

Historie Pokud má počítač jeden procesor a chceme mít spuštěno několik aplikací, musí operační systém strojový čas mezi aplikace dělit a správně je přepínat. 16 bitové verze Windows užívala kooperativní multitasking, každá aplikace měla vyhrazenu dobu na zpracování části kódu a puk musela předat řízení další aplikaci. Pokud něco přestalo komunikovat s okolím, celý systém zkolaboval. 32 bitový opační systém (od Windows 95) užívá preemptivní multitasking – rozdělení strojového času nezávisí na aplikacích a je plně řízeno operačním systémem. Poznámka: hroutění Windows vyplývá ze skutečnosti, že všechny spuštěné aplikace využívají část sdílené paměti, do které mají přístup všechny. Když nějaký program přepíše část paměti, která mu nenáleží, systém se z toho nezotaví.

Page 18: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

18

Prostředky po využití multitaskingu Události a správy Aplikace, které píšeme v Delphi jsou řízené událostmi: program většinu svého času čeká na událost. Když ji obdrží, provede její obsluhu a čeká dál.Příchozí zprávy jsou řazeny do fronty a obsluhovány až po zpracování předchozí zprávy. Pokud během obsluhy dojde k chybě nebo vznikne velmi dlouhá smyčka, program další aplikace nepustí ke slovu a jediná možnost je Ctrl Alt Del. Řešení spočívá buď v zpracování procesů na pozadí nebo použití časovačů. Zpracování procesů na pozadí Nejběžnější způsoby: • Zařadit do kódu volání metody Application.ProcessMessages, která zajistí zpracování všech zpráv

Windows, čekajících ve frontě • Jednotlivé kroky procesu provádět vždy, když aplikace obdrží událost OnIdle. V prvním případě se program věnuje plně zpracování procesu a zpracování ostatních zpráv povoluje jen nezbytně nutnou dobu. Ve druhém naopak aplikace běží jen když ve frontě nečeká žádná zpráva. V obou případech nemáme možnost jeden z procesů potlačit a druhý upřednostnit. Časovače Kód procesu, který má být zpracován na pozadí se rozdělí na malé části, které se vloží do obsluhy události OnTimer časovače. Pomocí intervalu časovače lze měnit rychlost zpracování, v případě potřeby vypnutím časovače proces zastavit.

Vlákna Shrnutí: Od Windows95 má každá aplikace vyhrazen čas, během něhož je zpracovávána procesorem. Po jeho uplynutí se aktivuje další úsek vyhrazený sousední aplikaci. Těmto úsekům, během nichž se provádějí části programů se říká vlákna. (thread) Rozdělení procesů se může dít nejen na úrovni aplikací, ale i v rámci jedné aplikace. Potřebujeme-li např. paralelně zpracovávat dva úkoly v jedné aplikaci, můžeme pro každý z nich vytvořit další vlákno přímo v této aplikaci. Vlákna pak běží současně a do jisté míry nezávisle. Třída TThread Je abstraktní třída nadefinovaná ve VCL, zapouzdřuje v sobě funkce potřebné pro práci s vlákny. Constructor Create(createsuspend:boolean) – konstruktor pro vytvoření instance vlákna. Má logický parametr, který rozhoduje o tom, jestli se vlákno spustí hned nebo se vytvoří pozastavené. ( s parametrem false se spouští hned) Prcedure Suspend – přeruší činnost běžícího vlákna Procedure Resume – opětné spouštění zastaveného vlákna Procedure Free – vlákno uvolní po skončení jeho práce Function Terminate: integer – ukončení běhu vlákna Function WaitFor: Integer – pozdrží vlákno do té doby, než jiné vlákno skončí. Procedure excecute;virtual;abstract; – metoda, kterou naprogramujeme (Override) co vlastně má blákno dělat. Procedure Synchronize(Method: Tthreadmethod) – viz dále Synchronizace vláken Pokud by v jednom programu běželo více vláken, mohlo by docházet ke konfliktům při práci s VCL. Proto je nezbytné, aby se zde vlákna synchronizovala a přistupovala k objektům VCL postupně. Synchronize – metoda, jejím parametrem je procedura, která přistupuje k VCL. Procedury volané tuto metodou mají být co nejkratší a mají obsahovat pouze příkazy, které používají VCL. Kromě toho je také třeba synchronizovat přístup ke společným proměnným. Možnosti pru tuto synchronizaci: • Kritické sekce • Čekání na vlákno • Mutexy Priority Každé vlákno může mít sedm stupňů důležitosti.

Page 19: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

19

TthreadPriority=(tpIdle, tpLowest, tpLower, tpNormal, tpHoghe,tpHighest, tpTimeCritical) Nastavení: vlakno.priority:=tpHigher

Příklady: 1. Multitasking: Chceme vytvořit text, který se posouvá na pozadí, mizí na jedné straně a na druhé se zase objevuje. (marquee). Pro řízení tohoto pohybu vyzkoušíme postupy: Application.Processmessages OniIdle Timer Vlastní posuv textu bude provádět jednoduchá funkce type … Timer1: TTimer; procedure IdleProc(Sender: TObject; var Done: Boolean); {defunuje co se ma provest OnIdle} procedure Timer1Timer(Sender: TObject); … var Form1: TForm1; k1,k2:boolean; implementation {$R *.DFM} function posunText(text:string):string; var s:string; begin s:=Copy(Text,1,1); {1. znak se zkopiruje do pomocne promenne} delete(text,1,1); {smaze se} result:=text+s; {prida se nakonec} end; procedure TForm1.FormCreate(Sender: TObject); begin k1:=true; k2:=true; {logicke promennu ukoncujici procesy} label1.caption:=label1.caption+' '; label2.caption:=label1.caption; label3.caption:=label1.caption; end; procedure TForm1.Button1Click(Sender: TObject); { Application.Processmessages} var i:integer; begin k1:=not k1; while not k1 do begin label1.caption:=PosunText(Label1.caption); for i:=0 to 100000 do {zpomal.smycka} Application.Processmessages {pokud se App.proc. vynecha, jde to vypnout jedine Ctrl Alt Del} end; end; {pokud bezi smycka posouvajici text, nelze okno uzavrit.

Page 20: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

20

protoze cekajici zpravy jsou sice obslouzeny, ale proces je stale aktivni. Chceme-li skoncit zavrenim formulare, je treba do metody OncloseQuery formulare vlozit prikaz k1:=true} procedure TForm1.IdleProc(Sender: TObject; var Done: Boolean); {Co se bud edit, kdyz processor nema na praci nic dulezitejsiho} var i:integer; begin for i:=1 to 100000 do; label2.caption:=posuntext(label2.caption); end; procedure TForm1.Button2Click(Sender: TObject); begin {kdyz ma program cas, posunuje textem} k2:=not k2; if not k2 then Application.OnIdle:=IdleProc else Application.onIdle:=nil; end; procedure TForm1.Button3Click(Sender: TObject); {timer} begin timer1.enabled:=not timer1.enabled; end; procedure TForm1.Timer1Timer(Sender: TObject); begin label3.caption:=posuntext(label3.caption); end; end. 2. Vlákna Naprogramujeme dvě vlákna, každé bude vykreslovat náhodné body na formulář. (Jedno červené, druhé modré). Umožníme nastavovat prioritu vláken prostřednictvím trackbaru, takže jedna z barev může převládat. type vlakno=class(tthread) private x,y:integer; b:tcolor; {barva vlakna} protected procedure execute;override; procedure maluj;{vykresleni bodu} public constructor create(bb:tcolor); end; TForm1 = class(TForm) CheckBox1: TCheckBox;{vyber spuštěni vlakna} CheckBox2: TCheckBox; TrackBar1: TTrackBar;{priorita jednoho z vlaken} TrackBar2: TTrackBar; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure CheckBox1Click(Sender: TObject); procedure CheckBox2Click(Sender: TObject); procedure TrackBar1Change(Sender: TObject); procedure TrackBar2Change(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end;

Page 21: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

21

var Form1: TForm1; v1,v2:vlakno; implementation {$R *.DFM} constructor vlakno.create(bb:tcolor); begin b:=bb; inherited create(false); end; procedure vlakno.maluj; begin form1.canvas.pixels[x,y]:=b; end; procedure vlakno.execute; var i:integer; begin randomize; repeat for i:=1 to 1000 do; x:=random(form1.clientwidth); y:=random(form1.clientheight); synchronize(maluj); Application.ProcessMessages; until terminated; end; procedure TForm1.FormCreate(Sender: TObject); begin v1:=vlakno.create(clred); v2:=vlakno.create(clblue); v1.suspend;v2.suspend; end; procedure TForm1.FormDestroy(Sender: TObject); begin v1.free;v2.free; end; procedure TForm1.CheckBox1Click(Sender: TObject); begin if checkbox1.checked then v1.resume else v1.suspend; end; procedure TForm1.CheckBox2Click(Sender: TObject); begin if checkbox2.checked then v2.resume else v2.suspend; end; procedure TForm1.TrackBar1Change(Sender: TObject); begin v1.priority:=tthreadpriority(trackbar1.position); end; procedure TForm1.TrackBar2Change(Sender: TObject); begin v2.priority:=tthreadpriority(trackbar2.position);

Page 22: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

22

end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin v1.Terminate; v2.Terminate; end; end. Cvičení: (Souvisí ještě s modelováním) Hra život Společenství organizmů se může vyvíjet v prostoru rozděleném na elementární jednotky. Organizace životního prostoru je pravidelná, můžeme si ji představit jako šachovnici.Každá jednotka má tedy 8 sousedů, čtyři podél stěn a čtyři ve směru úhlopříček. V každé jednotce se může marodit živočich, ten v ní také prožije celý život, nebude se stěhovat. Volný životní prostor obsazují noví živočichové. Vývoj společenství začíná v určité prvotní fázi, pak probíhá neustálá výměna generací, Nová generace vzniká jako důsledek tří současně probíhajících událostí: Narození: v prázdné jednotce, která má právě tři sousedy, se narodí nový živočich. Smrt: Organismus, který má nejvýš jednoho souseda umírá zoufalstvím, organismus, který má víc než tři sousedy umírá hlady. Přežití: Organismus se dvěma nebo třeni sousedy přežívá. Hrubý algoritmus hry: repeat podle pravidel 1-3 vytvoř novou generaci z nové generace udělej starou generaci until konec Ukončení hry: společnost vymře nebo vytvoří ustálený stav – budou se neustále opakovat dvě po sobě následující generace. (Zjednodušeno)

Řešení: simulováno dvojrozměrným statickým polem, zobrazeno do StringGridu. const n=14; type pole=array[0..n,0..n]of string; var Form1: TForm1; s,no:pole; {s stara generace, no-nova generace} implementation {$R *.dfm} procedure ukaz(a:pole); var i,j:integer; begin for i:=0 to n do for j:=0 to n do form1.stringgrid1.cells[i,j]:=a[j,i]; end; procedure TForm1.BitBtn3Click(Sender: TObject); var i,j,p:integer; begin randomize; for i:=0 to n do for j:=0 to n do begin p:=random(2); if p=0 then s[i,j]:='' else s[i,j]:='*'; end; ukaz(s);

Page 23: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

23

end; procedure TForm1.FormCreate(Sender: TObject); begin stringgrid1.ColCount:=n+1; stringgrid1.rowcount:=n+1; end; function sousede(a:pole;k,l:integer):integer; {pocet sousedu bunky [k,l]} var p,id,ih,jd,jh,i,j:integer; begin p:=0; {stredova bunka se nepocita} if k=0 then id:=0 {1.radek} else id:=k-1; if k=n then ih:=n{posledni radek} else ih:=k+1; if l=0 then jd:=0 {1.sloupec} else jd:=l-1; if l=n then jh:=n{posledni sloupec} else jh:=l+1; for i:=id to ih do for j:=jd to jh do if (k<>i) or (l<>j){neni stred} then if a[i,j]='*' then inc(p); result:=p; end; procedure TForm1.BitBtn1Click(Sender: TObject); var i,j:integer; begin for i:=0 to n do for j:=0 to n do begin no[i,j]:=''; if (s[i,j]='') and (sousede(s,i,j)=3) {narodi se novy organismus} then no[i,j]:='*'; if (s[i,j]='*') and((sousede(s,i,j)=2) or (sousede(s,i,j) =3)) then no[i,j]:='*';{preziti} end; s:=no; ukaz(s); end;

7. Úvod do databází

Základní pojmy ČSN 36900/1-1987 Data mn. Č údaje – obraz vlastnosti objektu, vhodně formalizovaný pro přenos, interpretaci nebo zpracování prostřednictvím lidí nebo automatů Informace – význam, který člověk přisuzuje údajům. Soubor – množina fyzických záznamů dat na diskové paměti počítače. Báze dat je množina souborů, které se užívají pro zabezpečení různých uživatelských funkcí.

Modelování reálného světa Podnik – organizační jednotka (klub sběratelů) Model – soubor nástrojů, který umožňuje odvodit obecné vlastnosti podniku. Datový model je soubor technik a nástrojů pro popis prvků a vztahů v podniku. Výsledkem modelování podniku je popis dat a vazeb mezi nimi – schéma báze dat.

Page 24: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

24

E-R model (Entity-Relation) – grafická metoda Typ entity Atribut (vlastnost) Typ vztahů mezi entitami

Příklad:

rok založení Vztahy mezi entitami N:1 (funkční) 1:N (hierarchický) N:M (síťový) 1:1 Příklady: vztahy mezilidské (polyandrie, polygamie, volné skupinové vztahy, běžné manželství) Počítačově realizovatelné modely Hierarchický, síťový (systémy se propojují pomocí ukazatelů), relační (tabulky) Tvorba databáze

• Přípravná fáze – návrh schéma báze dat (modelování reálného světa) • Technická fáze – pomocí databázového systému vytváříme databázi na počítači • Uživatelská fáze – užíváme databáze, aniž bychom museli projít předchozími etapami

Systémy řízení báze dat Systém programů pro správu databází – Paradox, Fox Pro, DBase,Access, Oracle, Informix, MySQL… Hlavní funkce databázového systém(DBS) DBS = báze dat + systém řízení báze dat

• Create zápis schémata databáze do počítače • Append přidávání nových záznamů • Edit úpravy záznamů • View zobrazování dat na obrazovce • Ask (Query) získání odpovědi na určitou otázku • Forms definice a využití specifických oken • Report tiskové sestavy • Sort třídění

Relační datový model Obecný tvar tabulky: sloupce(pole)

Jméno Příjmení …… Plat

Jiří Prouza 80 000

student Je člen klubu jméno

bydliště

věk název

adresa

poplatek

Page 25: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

25

Řádek (záznam)

Požadavky na tabulku: Všechny hodnoty elementární – tj. dále nedělitelné Pořadí sloupců je nevýznamné Pořadí řádků rovněž Sloupce jsou homogenní (údaje stejného druhu) Každý sloupec má jednoznačné jméno Řádky musí být rozlišitelné – tabulka nesmí obsahovat dva zcela stejné řádky Sloupec, který jednoznačně určuje řádky v tabulce se označuje jako primární klíč. Definování tabulek Příklad: Číslo sběratele Jméno Město Autíčko Cena 1 Jiří Kladno Fabia 200 1 Jiří Kladno Mercedes 100 2 Karel Praha Mercedes 100 2 Karel Praha Fabia 160 3 Tomáš Praha Trabant 300 Několikrát zbytečně stejné hodnoty – lepší rozdělit na tři samostatné Sběratel: Číslo sběratele Jméno Město Ulice Věk 1 Jiří Kladno Liberecká 32 13 2 Karel Praha Chámova 52 20 3 Tomáš Praha Růžová 36 15 Autíčka Číslo sběratele Číslo typu Cena 1 500 200 1 505 100 2 505 100 2 502 160 3 800 300 Typ auta Číslo typu popis 500 Fabia 505 Mercedes 502 Fabia žlutá 800 Trabant Výhody rozdělení: Jednoduchost a přehlednost, šetření paměti, pro propojení tabulek je nutnost společných sloupců. Celkem: Vytváříme malé a jednoduché tabulky, které lze propojit pomocí společných sloupců. K propojování většího množství tabulek se hodí uměle vytvořená číselná pole. Braňme nadbytečnosti – opakovatelnosti údajů a nevkládejme zbytečnosti. (sloupec lze vždy přidat) Příklady databází s propojenými tabulkami

Page 26: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

26

Databáze v Delphi Tabulky můžeme buď vytvářet programově pomocí formulářů nebo v Paradoxu, který je součástí Delphi. (Nebo v dalších databázových systémech) Nejprve se naučíme pracovat s hotovými tabulkami, které jsou k dispozici, pak zakládat nové databáze jednak v Paradoxu, jednak přímo v Delphi. Do formuláře umístíme neviditelné komponenty Table1 (paleta BDE) a DataSource1 (DataAccess), DBgrid1,DBEdit a DBNavigator ze záložky DataConrols. Datasource slouží k propojení údajů, Table je tabulka existující databáze a ostatní komponenty slouží pro práci s údaji. Propojení:

• Table1.DatabaseName Data (lze vybrat z hotových databází) • Table1.TableName Animals.db (lze vybrat) • Table1.Active TRUE • DataSource1.DataSet Table1 • DBgrid1.DataSource DataSource1 • DBImage. DataSource DataSource1 • DBImage.DataField BMP (lze vybrat) • DBEdit. DataSource DataSource1

Page 27: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

27

• DBEdit.DataField Name DatabaseName udává, se kterou databází bude komponenta Table1 pracovat. TableName pak určuje konkrétní tabulku. Jako DatabaseName lze u některých druhů databází (Paradox, DBase) uvést adresář nebo zástupné jméno – Alias. Table1 a Datasource1 jsou neviditelné a poskytují data ostatním komponentám. Komponenty ze skupiny DataControls se pak užívají jako ovládací a zobrazovací prvky. Už v režimu návrhu, jakmile Table1.active nastavíme na True, tabulka se otevře a načte data. Komponenta DBGrid dovoluje prohlížet i editovat záznamy (ukončení a potvrzení přechodem na další řádek, únik Esc), přidávat záznamy klávesou Insert a mazat záznamy Ctrl+Del. U dalších komponent kromě DataSource musíme nastavit DataField na pole, které chceme zobrazit. DBEdit – prohlížení a editace jednoho pole databáze textového typu. DBImage – prohlížení a editace jednoho pole databáze typu obrázek. (bitová mapa, možno vkládat přes schránku nebo použít metodu DBImage1.Picture. Loadfromfile(název obrázku)

Cvičení: 1. Navrhněte vlastní databázi s minimálně třemi propojenými tabulkami. 2. Využijte připravené databáze a připravte formulář pro práci s tabulkou Events.

8. Vytváření databáze v Paradoxu

Page 28: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

28

Tvorba nové tabulky Delphi/Tools/Database Desktop File/New/Table, potvrdíme Paradox7

Page 29: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

29

Názvy polí by měly splňovat pravidla pro identifikátory (Dosovské), typ vybereme ze seznamu. Každá tabulka musí mít primární klíč, podle kterého lze každý záznam jednoznačně identifikovat. Většinou k tomuto účelu volíme pole ID, obvykle typu Short nebo Long Integer nebo AutoIncrement. (Pole nevyplňuje uživatel, ale hodnoty dodává systém) K propojování je vhodnější první varianta. U některých polí je třeba zadat velikost (text – Alpha), primární klíč nastavíme dvojklikem v poli Key. Chceme-li tabulku dál třídit podle jiných kritérií, je vhodné nastavit v roletce Table properties Sekundární indexy. Pro jednotlivá pole lze nastavit minimální a maximální hodnoty, masky pro zadávání apod.

Po stisknutí OK ještě doplníme název indexu.

Strukturu tabulky uložíme pod vhodným jménem, (dá se ještě měnit – např. tlačítko Restructure panelu nástrojů), otevřeme ji (File/Open/Table) a po uvedení do editačního režimu – opět podobné tlačítko panelu nástrojů vpravo, můžeme zadávat údaje. Struktura našich tabulek:

Page 30: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

30

Ještě k tvorbě nové tabulky: – pokud to systém dovolí, vyberme nejdřív alias, abychom všechny tabulky měli uložené pohromadě. Tools/Alias manager – nejprve vytvoříme alias pro databasename Vložíme vytvořenou strukturu do vhodného adresáře (viz Alias) Tabulku otevřeme v DBDesktopu poklepáním na ikonu tabulky, kliknutím na poslední ikonu spustíme editační režim a můžeme vyplnit údaje a tabulku uložit..

Cvičení: Naplňte hodnotami tabulky z některé databáze, kterou jste navrhovali minulou hodinu. Dbejte na společná pole pro propojování a primární i sekundární indexy, alby se tabulky daly třídit.

9. Hodnoty polí Komponenta Table1 má vlastnost Fields, která se chová jako pole atributů. Prvky Fields jsou objekty typu TField, které mají mj. vlastnosti AsBoolean, AsCurrency, AsDateTime, AsFloat, asInteger, AsString, AsVariant sloužící pro přístup k hodnotě pole.(Variant je datový typ, kterým může být cokoliv – pohodlné, ale pomalé a zabírá hodně místa) Pole jsou číslována od nuly do FiledsCount -1. table1.fields[2].asstring – zobrazí hodnotu 3.pole aktuálního záznamu. (Pro Employee.db křestní jméno) Jinak: table1.fieldByName('FirstName').asstring

Page 31: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

31

Metoda FieldbyName vrací odkaz na objekt typu TField, který odpovídá atributu zadaného jména. Nevýhoda: Pokud v komponentě DBGrid přeházíme sloupce, Fileds[2] odpovídá jinému atributu. Editor polí Dvojklik na Table1, Add fileds Zatímco v předchozích řešeních proměnná typu TField vznikala za běhu programu, tímto způsobem ji máme k dispozici při návrhu programu. V definici třídy TForm přibyla pro každé pole jedna proměnná:

• Table1EmpNo: TIntegerField; • Table1LastName: TStringField; • Table1FirstName: TStringField; • Table1PhoneExt: TStringField; • Table1HireDate: TDateTimeField; • Table1Salary: TFloatField;

Inspektorem objektů lze editovat vlastnosti polí – Alignment (zarovnání), DisplayLabel(nadpis sloupečku v komponentě DBGrid), ReadOnly… Šířka sloupečků jde měnit přímo v komponentě DBGrid1.

Vypočítaná pole Příklad: chceme přidat do tabulky sloupec s měsíčním platem. Postup: Dvojklik na Table1 – editor polí – New Field Vyplníme Type a Field Type Pro komponentu Table1 napíšeme proceduru OnCalcFields Table1Msnplat.AsFloat:= Table1Salary.AsFloat/12 Tato procedura se volá při každém načítání záznamu a protože je dána programově, zobrazuje se až za běhu.

Vyhledaná pole V tabulce můžeme zobrazit i údaj vyhledaná pomocí jiné tabulky, je ovšem nutné tabulky propojit přes společné pole. Table1.TableName – Orders (objednávky), Table2.TableName – Customer.(zákazníci) –

propojíme přes CustNo – číslo zákazníka. Table1 zobrazíme přes DBGrid, Použijeme editor polí Table1 a vyplníme údaje podle obrázku. ORDERS obsahuje objednávky. Každá objednávka se vztahuje k určitému zákazníkovi – zákazník má CustNo číslo zákazníka. CUSTOMER je tabulka zákazníků, mezi její atributy patří také CustNo a Compamy – jméno společnosti.

Page 32: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

32

DBGRID1 zobrazí obsah tabulky ORDERS s přidaným sloupečkem Zákazník. Hodnota v něm se získá tak, že se v tabulce Customer (Dataset Table2)vyhledá záznam s hodnotou atributu CustNo (Lookup Keys=CustNo), která se rovná CustNo (KeyField ĆustNo) a z nalezeného záznamu vezme hodntu Company. (ResultField=Copany) Vyhledávaná pole mohou být zobrazena už v době návrhu, protože se na nich kód programu nijak nepodílí.

Sloupce tabulky Dvojklikem na komponentu DBGrid vyvoláme editor sloupců, tlačítkem Add All Fileds přidáme definici sloupců pro všechna pole a v inspektoru objektů nastavíme vlastnosti jednotlivých sloupců.

Ošetření akcí Nedovolí zapsat záznam s nevyplněným jménem: procedure TForm1.Table1AfterPost(DataSet: TDataSet); begin if table1lastname.IsNull then begin dbgrid1.selectedfield:=table1lastname; dbgrid1.setfocus; showmessage('vypln prijmeni'); abort end; end; Po zavolání metody post je před zápisem do databáze volána metoda Beforepost. Metoda DBgridu Selectedfiled udává, ve kterém sloupečku stojí kurzor. Vlastní dotaz, zda mazat záznam: procedure TForm1.Table1BeforeDelete(DataSet: TDataSet); begin if messagedlg('smazat'+table1lastname.asstring,mtconfirmation,[mbyes,mbno],0)<>mryes then abort; end; Nastavení výchozí hodnoty nového záznamu: procedure TForm1.Table1AfterInsert(DataSet: TDataSet); begin table1hiredate.AsDateTime:=date; table1salary.asfloat:=12*2000 end;

Cvičení: 1.Doplňte do tabulky nové pole pro hustotu obyvatel a upravte zobrazení tabulky podle vzoru:

Page 33: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

33

2. Vložte na formulář dva DBGridy, obsahující propojení tří tabulek: Customer-Orders, Employee-Orders (Kdyby nás zajímaly např. veškeré prodeje prodejců nebo naopak veškeré prodeje zákazníkům, bylo by třeba použít tzv. závislé tabulky. (dále)

3. Pracujte na databázovém projektu s vlastními tabulkami. Řešení: 1. procedure TForm1.Table1CalcFields(DataSet: TDataSet); begin Table1Density.asfloat:=round(table1population.AsFloat/table1area.asfloat*100)/100 end;

10. Hledání, třídění a filtrování, závislost tabulek

Vybrané záznamy (Filtrování) Nastavením filtru se záznamy omezí na ty, které vyhovují dané podmínce. Je-li možné použít jako filtr řetězcovou konstantu: Table1.Filter:= 'Salary < 30000'; Table1.filtered:=true; Filtr může obsahovat i logické spojky, (State = 'CA' or State = 'MA') případně částečnou shodu: State = 'M*' vybere stát začínající na M. Výhodné je za běhu programu nastavovat filtr přes nějaký text: Table1.filter:=Memo1.text Jiný způsob: Následující příklad vybere zaměstnance přijaté v určitý den týdne. (neděle je 0) procedure TForm1.Button2Click(Sender: TObject); begin table1.filtered:=true;

Page 34: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

34

end; procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean); begin accept:=dayofweek(table1Hiredate.asdatetime)=strtoint(edit1.Text) end; metoda OnFilterrecord se volá pro každý právě načítaný záznam, accept určuje, zda se záznam načte. Pozor – je-li také vyplněna vlastnost Filter, zobrazí se jen záznamy vyhovující oběma podmínkám. Pokud jsou s načítáním filtru nějaké problémy, je výhodné použít funkci, která převádí řetězec na řetězce v apostrofech. function QuotedStr(const S: string): string; Table1.Filter := 'continent = ' + QuotedStr( combobox1.Items[combobox1.itemindex]); table1.filtered:=true;

Vyhledání záznamu Pokud je tabulka setříděná podle nějakého pole, můžeme použít logickou funkci findKey. Její parametr píšeme do hranatých závorek – je pole s proměnnou velikostí. (open arrray) If table1.FindKey([edit1.text]) Když existuje záznam s danou hodnotou pole (v tomto případě číslo záznamu jako string), přesuneme se na něj a funkční hodnota je true. Jinak funkce vrací false.

Třídění Tabulka je obvykle setříděna podle jednoho údaje (nebo skupiny údajů)=primární klíč. Chceme-li záznamy procházet v jiném pořadí, potřebujeme sekundární index – něco jako soubor setříděný podle hodnot jiných polí a obsahující odkazy do primárního souboru. (obsahuje jen hodnoty těchto polí). Sekundární indexy jsou součástí definice tabulky. Table1.Indexname udává podle kterého klíče (primární, některý ze sekundárních) chceme tabulku procházet. Nastavení klíče ovlivňuje funkci metod First, Last, Next a Prior. K nastavení setřídění se dá také použít vlastnost indexFiledNames, dosazení do této vlastnosti vynuluje vlastnost Indexname a naopak. table1.IndexName:='byname'; Stavy tabulky – nejpohodlněji obsluhujeme s db navigátorem. Table1.state –table1.insert (vkládání záznamu -+ na db navigátoru apod,) Edit, Post, Cancel

Závislost tabulek Příklad – druhá tabulka obsahuje objednávky zákazníka vybraného v první tabulce. Table1.tablename – customer.db Table2.tablename – orders.db Každou tabulku propojit s příslušným datasource a Dbgrid. Vytvoření závislosti: Table2.mastersource – datasource1 Vyvoláme dialog pro nastavení vlastnosti Table2.masterfields, kde vyplníme, jak bude podřízená (detail) tabulka záviset na nadřízené. (master). Tato závislost se vždy vztahuje ke klíči, podle kterého je tabulka setříděná. Detail Fields – atributy tvořící klíč podřízené tabulky Master Fields – atributy nadřízené tabulky. Ze seznamu Available indexes (dostupné indexy) vybereme položku CustNo, pak ji označíme v detail fields i Master fields a stiskem tlačítka Add přidáme toto propojení do propojených atributů. (Joined fields)

Page 35: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

35

V tabulce Table2 pak budou dostupné pouze záznamy, jejichž hodnota CustNo odpovídá téže hodnotě aktuálního záznamu v Table1. Závislá tabulka může být nadřízenou jiné tabulky…

Cvičení: 1. Nastavte filtr podle následujících obrázků: (country.db)

2. Doplňte do tabulky Country.db indexy DleRozlohy a Dlepopulace, nastavte třídění a vyhledávání podle názvu země, rozlohy a počtu obyvatel. 3. Nastavte tři závislé tabulky podle obrázku, abystě pro každého zaměstnance mohli zobrazit jeho objednávky a pro aktuální objednávku příslušného zákazníka. 4. Pracujte na databázovém projektu s vlastními tabulkami

Řešení: 1. procedure TForm1.ComboBox1Click(Sender: TObject); begin Table1.Filter := 'continent = ' + QuotedStr(

Page 36: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

36

combobox1.Items[combobox1.itemindex]); table1.filtered:=true; end; procedure TForm1.BitBtn1Click(Sender: TObject); begin table1.filter:='Capital='+QuotedStr(edit1.Text)+'or Capital='+ QuotedStr(edit2.Text) ; table1.filtered:=true; end; 2. procedure TForm1.Button2Click(Sender: TObject); begin table1.IndexName:= 'DleJmena'; end; procedure TForm1.Button3Click(Sender: TObject); begin table1.IndexName:= 'DleRozlohy'; end; procedure TForm1.Button4Click(Sender: TObject); begin table1.IndexName:= 'DlePopulace'; end; procedure TForm1.Button1Click(Sender: TObject); begin If not table1.FindKey([edit1.text])then showmessage('neexistuje') end; 3. Employee a Orders propojíme přes Empno (V Orders je třeba vytvořit sekundární index), oOrders a Customer přes CustNo.

11. Tvorba vlastní tabulky, pohyb po tabulce a výpočty

Pohyb po tabulce a výpočty Průměrný plat: procedure TForm1.Button1Click(Sender: TObject); var p:integer; s:real; begin p:=0;s:=0; table1.First; while not table1.Eof do begin s:=s+table1salary.asfloat; inc(p); table1.Next; end; showmessage(FloatTostrF(s/p,fffixed,10,2)) end; Metody komponenty Table1 First, Last, Next, Prior – pro přesun mezi záznamy EOF je True na konci databáze (předtím se volalo Last nebo neúspěšně Next) Analogicky BOF. Pokud nechceme, aby bylo vidět pohyb po záznamech (mj. zpomalení programu), vložíme příkaz Table1.DisableControls, díky kterému ovládací prvky přestanou reagovat na změny hodnot. Chráněný blok v programu (try-finally-end) zaručuje, že při přerušení výpočtu se provede opětné připojení řídících prvků metodou Table1.EnableControls. (Viz Výjimky)

Page 37: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

37

Záložky Chceme-li se po akci spojené s procházením tabulky vrátit na původní místo, použijeme záložku – vlastnost tabulky Bookmark. Var z:TBookmark; …… z:=table1.GetBookmark; vytvoří záložku=objekt, popisující aktuální pozici v tabulce. Table1.GotoBookmark(z) přejde na pozici určenou záložkou Table1.Freebookmark (z) – uvolní nepotřebnou záložku.

Vytvoření naové tabulky programově: Na formulář umístíme DBGrid, Datasource a Table1, propojíme je. Table1.DatabaseName vyplníme Alias nebo adresář, kde chceme tabulku vytvořit. procedure TForm1.Button1Click(Sender: TObject); begin Table1.tablename:= 'nova.db'; table1.FieldDefs.Add('cislo',ftAutoInc,0,true); table1.FieldDefs.Add('jmeno',ftstring,20,true); table1.FieldDefs.Add('prijmeni',ftstring,20,true); table1.CreateTable; table1.open; end; FieldDefs obsahuje definice polí, IndexDefs definice indexů. Parametry metody Add udávají jméno, typ, velikost a zda musí být údaj vyplněn. Metoda CreateTable vytvoří novou tabulku. Otevření už vytvořené tabulky (aby se nesmazala) procedure TForm1.Button2Click(Sender: TObject); begin table1.TableName:='nova.db'; table1.open; end; Více – nápověda Delphi The following example shows how to create a table. with Table1 do begin Active := False; DatabaseName := 'DBDEMOS'; TableType := ttParadox; TableName := 'CustInfo'; { Don't overwrite an existing table } if not Table1.Exists then begin { The Table component must not be active } { First, describe the type of table and give } { it a name } { Next, describe the fields in the table } with FieldDefs do begin Clear; with AddFieldDef do begin Name := 'Field1'; DataType := ftInteger; Required := True; end; with AddFieldDef do begin Name := 'Field2'; DataType := ftString;

Page 38: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

38

Size := 30; end; end; { Next, describe any indexes } with IndexDefs do begin Clear; { The 1st index has no name because it is { a Paradox primary key } with AddIndexDef do begin Name := ''; Fields := 'Field1'; Options := [ixPrimary]; end; with AddIndexDef do begin Name := 'Fld2Indx'; Fields := 'Field2'; Options := [ixCaseInsensitive]; end; end; { Call the CreateTable method to create the table } CreateTable; end; end;

Cvičení: 1. Pracujte na databázovém projektu s vlastními tabulkami 2. Pracujte s tabulkou Country, vyhledejte zemi s maximální rozlohou, ošetřete záložky. 3.Vyhledejte nejlidnatější zemi Jižní ameriky, použijte ošetření výjímek při vypnutí ovládacích prvků.

Řešení: 2. procedure TForm1.Button1Click(Sender: TObject); Var z:TBookmark; max:real;kdo:string; begin z:=table1.GetBookmark; table1.First; max:=0;kdo:=''; while not table1.Eof do begin if table1area.asfloat>max then begin max:=table1area.asfloat ; kdo:=table1name.asstring end; table1.Next; end; showmessage(FloatTostrF(max,fffixed,10,2)+#13+ kdo); Table1.GotoBookmark(z); Table1.Freebookmark (z) end; procedure TForm1.Button2Click(Sender: TObject); var max:real;kdo:string; begin Table1.DisableControls; try table1.First; max:=0;kdo:=''; while not table1.Eof do begin if table1continent.asstring='South America'

Page 39: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

39

then if table1population.asfloat>max then begin max:=table1population.asfloat ; kdo:=table1name.asstring end; table1.Next; end; showmessage(FloatTostrF(max,fffixed,10,2)+#13+ kdo); finally Table1.EnableControls; end; end;

12. SQL Je databázový dotazovací jazyk. Pořadí dotazů na databázi:select – from – where Select uvádí seznam sloupců (polí) v relaci From uvádí seznam tabulek, na které se klade dotaz Where kvalifikuje dotaz pomocí podmínek Komponenta Query (TQuery a TTable jsou DBE komponenty pro přístup k datům) má vlastnost SQL typu TStrings, který obsahuje příslušný dotaz jako řetězec. Ten se odesílá databázovému serveru (u tabulek Paradox, DBase pouze simulace), ten provede příkazy dotazu a pošle zpět data jako odpověď. Query1.Databasename nastavíme na DBDemos, přes dataset propojíme s DBGridem a můžeme vyzkoušet přímé zadání dotazů do mema:´ procedure TForm1.Button1Click(Sender: TObject); begin query1.SQL:=memo1.Lines; query1.open; end; SELECT * FROM CUSTOMER Zobrazí všechny záznamy tabulky SELECT COMPANY,CITY FROM CUSTOMER Jen sloupce Company a city SELECT COMPANY,CITY FROM CUSTOMER WHERE STATE=’CA‘ Jen sloupce Company a city, pro firmy z Kalifornie SELECT COMPANY,CITY FROM CUSTOMER WHERE STATE=‘CA‘ and City<’P‘ Jen sloupce Company a city, pro firmy z Kalifornie, města abecedně před P SELECT COMPANY,CITY FROM CUSTOMER WHERE Company LIKE ‘%Div%‘ Zobrazí záznamy firem obsahujících ve svém názvu řetězec Div SELECT State,COMPANY,CITY FROM CUSTOMER ORDER BY State, City, Company (ORDER BY State, city DESC,Company) Záznamy uspořádané lexikograficky podle státu, města, názvu firmy. (city DESC, -setřídění podle tohoto atributu bude sestupné) SELECT Company, City||”, “|| State FROM CUSTOMER Výsledek dotazu bude obsahovat atribut město a stat (sloupec City, State) Ke spojování řetězců slouží operátor ||, textové konstanty se uzavírají mezi uvozovky. SELECT FirstName, LastName, Salary/12 FROM EMPLOYEE Výsledek dotazu bude zahrnovat pole s měsíčním platem SELECT FirstName, LastName, Salary/12 as Mesicni FROM EMPLOYEE ORDER BY Mesicni

Výsledek dotazu bude zahrnovat pole s měsíčním platem, abychom tuto položku mohli uvést v ORDRER BY, je třeba ji pojmenovat – klíčové slovo AS

SELECT AVG(Salary) FROM EMPLOYEE Vypočítá průměrný plat Další funkce: MIN, MAX, SUM, COUNT SELECT State, COUNT(Company) AS pocet FROM CUSTOMER

Page 40: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

40

GROUP BY STATE ORDER BY POCET DESC Výsledek : seznam států a počet zákazníků v nich. GROUP BY – seskupit podle Propojování tabulek SELECT Company, COUNT(OrderNo) FROM CUSTOMER, ORDERS WHERE CUSTOMER.CustNo=ORDERS.CustNo GROUP BY Company Vrací seznam společností a počty jejich objednávek.

Dotaz požaduje záznamy tabulky Customer a Orders, podmínkou WHERE vybíráme pouze dvojice, které se shodují v atributu CustNo (číslo zákazníka)

SELECT Company, OrderNo, Description FROM CUSTOMER, ORDERS,ITEMS,PARTS WHERE CUSTOMER.CustNo=ORDERS.CustNo and ORDERS.OrderNo=ITEMS.OrderNo and ITEMS.PartNo=Parts.PartNo ORDER BY Company

Pro každou společnost zobrazí prvky objednávek, spojovat lze i pomocí atributů, které nejsou obsaženy ve výsledku

SELECT Description, COUNT(Qty), SUM(Qty) AS Pocet FROM ITEMS,PARTS WHERE ITEMS.PartNo=Parts.PartNo GROUP BY Description ORDER BY Pocet DESC Zobrazí seznam druhů zboží s počtem objednávek a počtem kusů Spojení tabulek je použito k získání atributu Description – název zboží.

Count(Qty) – (atribut Qty udává objednané množství) vypočítá počet záznamů se stejnou hodnotou Description (klauzule Group By) SUM(Qty) – součet – tj množství objednané celkem ve všech objednávkách

Změny v tabulkách INSERT INTO CUSTOMER (CustNo,Company,ADDr1) VALUES (777,“RUM software“,“Poltava 261“) Vloží záznam do tabulky s uvedenými hodnotami atributů DELETE FROM CUSTOMER WHERE CustNo=777 Vymaže záznam vyhovující podmínce UPDATE EMPLOYEE SET Salary=Salary+100 WHERE HireDate<”1.6.1990” Zvýší plat o 100 každému zaměstnanci přijatému před daným datem Server změny provede, ale nevrací data. (nutno zobrazit zvlášť)

Cvičení: 1. Tabulka country: Zobrazte počet zemí v jednotlivých kontinentech Zobrazte celkovou plochu zemí na kontinentech

Page 41: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

41

2. Tabulky Customer, Orders, employee Zobrazte společnost kupce, příjmení prodejce, zaplacenou částku a datum prodeje.

Zobrazte pro každého prodejce počet prodejí 3. Pracujte na databázovém projektu s vlastními tabulkami

Řešení: 1. SELECT Continent, COUNT(name) AS pocet FROM country GROUP BY continent ORDER BY POCET DESC SELECT Continent, Sum(area) AS Celkova_plocha FROM country GROUP BY kontinent 2. SELECT Customer.Company, Employee.LastName,Orders.AmountPaid,Orders.Saledate FROM CUSTOMER, ORDERS,Employee WHERE Customer.CustNo=ORDERS.CustNo and Employee.EmpNo=Orders.EmpNO 3. SELECT LastName as prodejce,count(LastName) as Pocet_Prodeji FROM ORDERS,Employee WHERE Employee.EmpNo=Orders.EmpNO Group by Lastname

13. Úvod do počítačové grafiky – grafické komponenty Následující kapitoly se budou zabývat počítačovou grafikou z hlediska některých jejích algoritmů. Každá komponenta umožňující práci s grafikou má vlastnost Canvas typu TCanvas. Ta vytváří pracovní plochu, na kterou se dá kreslit, případně pracovat s obrázky. Sama třída plátna obsahuje všechny metody potřebné pro kreslení. Dá se užít canvas formuláře, ale ten si nepamatuje obrázek. Lepší je užít komponentu Image, jejíž vlastnost picture pak jde uložit , eventuelně otevřít přes Opendialog nebo Savedialog. procedure TForm1.Button2Click(Sender: TObject); begin if Opendialog1.execute then Image1.Picture.Loadfromfile(Opendialog1.FileName); end; Picture umí pracovat s formáty bmp, wmf, případně uživatelsky definovanými formáty. (picture.bitmap, případně Picture.graphic. Pokud před spuštěním načtete obrázek .jpg, dá se použít, ale ne dál upravovat) Plocha komponenty Image zbělá teprve při kreslení – prostor se vytvoří až při naplnění vlastnosti picture.bitmap.)

Některé metody a vlastnosti canvasu: Brush,color – barva výplně Pen.color – barva kreslicího pera Pen.width – tloušťka Moveto(x,y) – přesun na pozici x,z Lineto(x,y) – čára z aktuální pozice na pozici x,y Rectangle(a,b,c,d); – obdélník, a,b souřadnice levého horního, c,d pravého dolního rohu Elipse(a,b,c,d) – elipsa vepsaná tomuto obdélníku

Page 42: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

42

Pixels[x,y]:=clred; – bod o souřadnicích x,y se vybarví červeně. TextOut(x,y,’text’) – vypíše text na dané souřadnice. Vlatnosti textu – viz nápověda, font. Font – font s dalšími vlastnostmi – style, (fsbold…),color,size…

Kreslení grafu funkce: Princip je jasný – každému x přiřadíme právě jedno y podle funkčního předpisu a zakreslíme příslušný bod. Je ovšem třeba převést souřadnice – na papíru má obvykle střed souřadnice [0,0], na formuláři [clientwidth div 2, clientheight div 2], x-ová souřadnice roste v obou případech doprava, y-ová na papíru roste směrem vzhůru, na obrazovce směrem dolů. Podle volby funkce je také třeba volit jednotku – vhodný počet pixelů. Příklad: funkce y=3sinx procedure TForm1.Button1Click(Sender: TObject); var x,y:real; {skutecne souradnice} xx,yy,j:integer; }obrazovkove souradnice} begin j:=spinedit1.Value; {uživatelské nastaveni jednotky–pro sinus radove desitky px} for xx:=1 to image1.Width do {pro všechny body formulare} begin x:=(xx-image1.Width div 2)/j;{prevod na realne souradnice} y:=3*sin(x); yy:=-round(y*j)+image1.height div 2;{prevod na obrazovkove souradnice} image1.Canvas.pixels[xx,yy]:=clblue; {nakresleni bodu} end; end;

Cvičení 1. Naprogramujte kreslení grafů standardních funkcí af(b(x+c))+d, kde a, b, c, d jsou reálné konstanty. Využijte možnost definování uživatelské funkce, abyste používali jedinou proceduru pro kreslení obecné funkce f.´ 2. Naprogramujte kreslicí editor typu PaintBrush.

Řešení 1. implementation {$F+} {$R *.DFM} type ufce=function(x:real):real; function si(x:real):real; begin si:=sin(x); end; function co(x:real):real; begin co:=cos(x); end; function ex(x:real):real; begin ex:=exp(x); end; function dr(x:real):real; begin dr:=sqr(x); end; function ab(x:real):real; begin ab:=abs(x);

Page 43: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

43

end; function sq(x:real):real; begin if x>=0 then sq:=sqrt(x); end; procedure kresli(f:ufce;b:tcolor); var j,r,o,xx,yy:longint;x,y:real; c,d,k,q,p:real; begin j:=form1.spinedit1.value ; k:=strtofloat(form1.edit3.text); c:=strtofloat(form1.edit1.text); d:=strtofloat(form1.edit2.text); p:=strtofloat(form1.edit4.text); r:=form1.clientwidth div 2; o:=r; while r<form1.clientWidth do begin r:=r+j; o:=o-j; form1.Canvas.MoveTo(r,form1.clientHeight div 2 -2); form1.Canvas.lineto(r, form1.clientHeight div 2 +2); form1.Canvas.MoveTo(o,form1.clientHeight div 2 -2); form1.Canvas.lineto(o, form1.clientHeight div 2 +2); end; form1.canvas.pen.color:=b; for xx:=0 to form1.clientwidth do begin x:=(xx-form1.clientwidth div 2) /j; y:=d+k*f(p*(x+c)); yy:=-round(y*j)+form1.clientheight div 2; form1.canvas.pixels[xx,yy]:=b; end; end; procedure TForm1.sin1Click(Sender: TObject); begin kresli(si,clred); end; procedure TForm1.fce1Click(Sender: TObject); begin canvas.pen.color:=clblack; canvas.moveto(0,clientheight div 2); canvas.lineto(clientwidth, clientheight div 2); canvas.moveto(clientwidth div 2,0); canvas.lineto(clientwidth div 2,clientheight); end; procedure TForm1.cos1Click(Sender: TObject); begin kresli(co,clblue); end; procedure TForm1.exp1Click(Sender: TObject); begin kresli(ex,clwhite); end; procedure TForm1.x21Click(Sender: TObject); begin kresli(dr,clgreen); end; procedure TForm1.x1Click(Sender: TObject); begin

Page 44: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

44

kresli(ab,clyellow); end; procedure TForm1.FormCreate(Sender: TObject); begin spinedit1.value:=50; edit3.text:='1'; edit2.text:='0'; edit1.text:='0'; edit4.text:='1'; end; procedure TForm1.sqrtx1Click(Sender: TObject); begin begin kresli(sq,clolive); end; end; procedure TForm1.clear1Click(Sender: TObject); begin canvas.pen.color:= clbtnface; canvas.Brush.Color:=clbtnface; canvas.Rectangle(0,0,clientwidth,clientheight); end; end. 2. – jen pro inspiraci procedure TForm1.FormCreate(Sender: TObject); var i:integer; begin for i:=0 to 12 do begin image1.canvas.Brush.Color:=rgb(20*i,0,0); image1.canvas.rectangle(50*i,1, 50*i+49,50); end; jedu:=false; end; procedure TForm1.Image2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin jedu:=true; image2.Canvas.MoveTo(x,y); end; procedure TForm1.Image2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if jedu then image2.canvas.lineto(x,y); end; procedure TForm1.Image2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin jedu:=false; end; procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

Page 45: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

45

begin if button=mbleft then image2.Canvas.Pen.Color:= image1.Canvas.pixels[x,y]; end;

14. Algoritmus kreslení úsečky, animace Často opakované úlohy je třeba optimalizovat, jako ukázku uvedeme: Bresenhamův algoritmus pro kreslení úsečky. Výstupem je rastr, zobrazovací plocha je reprezentována maticí bodů, pixelů, zařízení řídí intenzitu a barvu každého pixelu.Pixel je dán svými souřadnicemi.

Mřížkové body jsou zobrazitelné body obrazovky. (pixely) Abychom nakreslili úsečku, je třeba zobrazit jí nejbližší mřížkové body. Kromě algoritmu pro úsečku existují další pro oblouk kružnice, ořezávání, výplně…

Úsečka z bodu [0,0] do bodu [xk,yk] : y = k

k

xy

x

For x:=0 to k do begin y:=round(k

k

xy

*x);

canvas.pixels[x,y]:=clblue; End; Nevýhody: Zaokrouhlování, násobení, neceločíselná aritmetika => pomalé

Bresenhamův algoritmus 1.oktant: 0<=yk<=xk (Pro další oktanty se postupuje analogicky) Vyjdeme z počátku a nahrazujeme úsečku požadovaným sledem bodů. Spojnice sousedních bodů sledu jsou buď rovnoběžné s x nebo s ní svírají úhel 45o. Úsečka je potom modelována řadou bodů s x –ovými souřadnicemi 0,1,…xk, y-ové vypočítáme. Koncový bod sledu [xk, yk] Z bodu [xj, yj] jdeme buď do bodu [xj+1, yj] nebo do bodu [xj+1, yj+1], Podle toho, který je blíž bodu dané úsečky .

Rozhodující prvek d: (1. obrázek)

[xk, yk]

[0, 0]

Page 46: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

46

Když 21

<k

k

xy

pak 02 <− kk xy

Označme: d= kk xy −2 Podle něj rozsvěcíme 1. vedlejší bod.

Pro 2. sousední bod vypočítáme další rozhodující prvek: Když 212 <

k

k

xy

tak 02

4<

k

kk

xxy

a tedy dnový

=4yk-xk = d+2yk´ Když označíme 2yk = p1 dnový = p1+d Pokud ovšem (2. obrázek)

232 <

k

k

xy

tak 02

34<

k

kk

xxy

a tedy dnový = 4yk -3xk =d+2 yk-2xk 2 yk-2xk = p2 pak dnový = p2+d

procedure úsečka (xk,yk:integer); { ve druhém oktantu stačí vyměnit x a y} var x,y,d,p1,p2:integer; begin d :=2*yk-xk ; p1 :=2*yk ;

p2 :=2*(yk-xk) ; x :=0 ;y :=0 ; { násobení a dělení před cyklem}

canvas.pixels[x,y]:=clblue; while x<xk do begin inc(x); if d<0 then d:=d+p1 else begin d:=d+p2; y:=y+1; end;

canvas.pixels[x,y]:=clblue; end; end;

Animace – vymazání a následné objevení posunutého obrázku umísťujeme do metody OnTimer Pohyb po přímce: nejlépe Bresenhamův algoritmus, jinak z počátku: y=round(yk/xk*x), z bodu x1,y1 do bodu x2, y2… y=round((y2-y1)/(x2-x1)*x+(y1x2-y2x1)/(x2-x1)) (přímka dána dvěma body) – proměnným parametrem je x Pohyb po kružnici – také nejlépe Bresenham, jinak parametrická rovnice: x:= xs+round(cos(fi)*r); y := ys+round(sin(fi)*r); – poloměr, xs,ys souřadnice středu, fi – úhel v radiánech Pohyb po elipse x:= xs+round(cos(fi)*r); y := ys+round(sin(fi)*r); a,b – poloosy

Cvičení: 1. Vyzkoušejte animaci několika souvisejících obrázků, umožněte nastavit rychlost. 2. Vyzkoušejte pohyb grafického objektu po lomené čáře – např. jeho odrážení o okraje formuláře a kružnici.(Můžete buď vytvořit objekt nebo použít nějakou hotovou komponentu – např. shape) Řešení:

Page 47: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

47

var Form1: TForm1; var i, v,s,xs,ys,r:integer;fi:real; procedure TForm1.FormCreate(Sender: TObject); begin timer1.enabled:=false; s:=10;v:=10; i:=1; fi:=0; timer2.enabled:=false; xs:=clientwidth div 2; ys:=clientheight div 2; r:=150; shape2.left:= xs+round(cos(fi)*r); shape2.top := ys+round(sin(fi)*r); end; procedure TForm1.Button1Click(Sender: TObject); begin timer1.enabled:=not timer1.enabled; end; procedure TForm1.Timer1Timer(Sender: TObject); begin if shape1.left<0 then v:=10; if shape1.left> clientwidth-shape1.width then v:=-10; if shape1.top<0 then s:=10; if shape1.top> clientheight-shape1.height then s:=-10; shape1.left:=shape1.left+v; shape1.top:=shape1.top+s; image1.picture.loadfromfile('prerod'+inttostr (i mod 6 +1)+'.bmp'); inc(i); end; procedure TForm1.SpinEdit1Change(Sender: TObject); begin timer1.interval:=spinedit1.value; timer2.interval:=spinedit1.Value; end; procedure TForm1.Button2Click(Sender: TObject); begin timer2.enabled:=not timer2.enabled; end; procedure TForm1.Timer2Timer(Sender: TObject); begin fi:=fi+0.1; shape2.left:= xs+round(cos(fi)*r); shape2.top := ys+round(sin(fi)*r); end;

15. Rastrová grafika Algoritmy rastrové grafiky vycházejí z počítání polohy jednotlivých pixelů. Vybarvení jednotlivého bodu: canvas.pixels[x,y]:=barva Při aplikaci efektů nějakým způsobem přepočítáváme souřadnice bodů. Na formulář umístíme dvě komponenty image, do jedné načteme bitovou mapu a do druhé ji budeme zobrazovat po různých úpravách. Vymazání obrázku

Page 48: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

48

image1.Canvas.Brush.color:=clwhite;; image1.Canvas. rectangle(0,0,image1.Width,image1.Height) Načtení obrázku ze souboru (.bmp) if opendialog1.execute then image1.picture.loadfromfile(opendialog1.FileName); end; Kopie var x,y:integer; begin for x:=0 to image1.Width do for y:=0 to image1.Height do image2.Canvas.pixels[x,y]:= image1.Canvas.pixels[x,y] end; Převrácení for x:=0 to image1.Width do for y:=0 to image1.Height do image2.Canvas.pixels[x,y]:= image1.Canvas.pixels[x,image2.Height-y]; Získání červené složky obrázku Při práci s barvami můžeme používat funkci rgb(x,y,z), kde x, z,y jsou od nuly do 255 nebo hexadecimální reprezentaci $abc, kde a, b,c jsou šestnáctková čísla 00 – FF. $0000FF je červená Operátor and se užívá k bitovému součinu čísel – tedy k vybrání určitých bitů z čísla, operátor shr provádí bitový posun čísla o zadaný počet bitů doprava var x,y:integer;c:tcolor; b:byte; begin for x:=0 to image2.Width do begin image2.Repaint; {prekresleni obrazku} for y:=0 to image2.Height do begin c:=image1.Canvas.pixels[x,y]; b:=(c and $FF0000) shr 16; image2.Canvas.Pixels[x,y]:= b; end; end; end; Převedení obrázku na šedivý Různé barvy přispívají různou mírou k celkovému jasu. Program vypočítá světlost jako vážený průměr a vynásobí jím $010101, což je tmavošedá. const rp=0.2989; {podil cervene} gp=0.5866; {zelene} bp=1-rp-gp;{modre} var x,y:integer;c:tcolor; r,g,b:byte; begin for x:=0 to image2.Width do begin image2.Repaint; for y:=0 to image2.Height do begin c:=image1.Canvas.pixels[x,y]; r:=(c and $0000FF); g:=(c and $00FF00) shr 8; b:=(c and $FF0000) shr 16; image2.Canvas.Pixels[x,y]:= round(r*rp+g*gp+b*bp)*$010101; end; end; end;

Page 49: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

49

Inverze var x,y:integer;c:tcolor; r,g,b:byte; begin for x:=0 to image2.Width do begin image2.Repaint; for y:=0 to image2.Height do begin c:=image1.Canvas.pixels[x,y]; r:=(c and $0000FF); g:=(c and $00FF00) shr 8; b:=(c and $FF0000) shr 16; r:=255-r; g:=255-g; b:=255-b; image2.Canvas.Pixels[x,y]:= r+g shl 8 +b shl 16; {shl posouva bity doleva} end; end; end; Zvětšenina Budeme třikrát zvětšovat oblast kolem bodu o souřadnicích 100,100 var x,y,x2,y2:integer; begin for x:=0 to image2.width-1 do begin image2.repaint; for y:=0 to image2.height-1 do begin x2:=100+x div 3; y2:= 100+y div 3; image2.Canvas.pixels[x,y]:=image1.Canvas.pixels[x2,y2]; end; end; end; Deformace var x,y,x2,y2:integer; begin for x:=0 to image2.width-1 do begin image2.repaint; for y:=0 to image2.height-1 do begin x2:=x+round(20*sin(y/50)); y2:= y+round(20*cos(x/50)); image2.Canvas.pixels[x,y]:=image1.Canvas.pixels[x2,y2]; end; end; end; Zvětšenina Bod, na jehož okolí se chceme podívat lupou vybereme kliknutím do výchozího obrázku. Zvětšení se zmenšuje se vzdáleností od vybraného bodu, nad určitou vzdálenost je 1. var x0,z0:integer; … procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin x0:=x;y0:=y; end; procedure TForm1.BitBtn6Click(Sender: TObject);

Page 50: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

50

var r,x,y,x2,y2:integer;z:real; begin for x:=0 to image2.width-1 do for y:=0 to image2.height-1 do begin image2.repaint; r:=sqr(x-x0)+sqr(y-y0); if r>10000 then z:=1 else try z:=10000/r except z:=100; end; x2:=round(x0+(x-x0)/z); y2:=round(y0+(y-y0)/z); image2.Canvas.pixels[x,y]:=image1.Canvas.pixels[x2,y2]; end; end;

Cvičení Vyzkoušejte si uvedené algoritmy.

16. Vektorová grafika Výsledkem použití kreslicích metod canvasu je změna barvy jednotlivých pixelů. Informace, jak k této změně došlo je ztracená. Chceme-li nakreslené objekty dodatečně upravovat, musíme si pamatovat jejich seznam a vlastnosti. Hodí se například pole nebo spojový seznam záznamů či objektů. Příklad 1. Levou myší kreslíme na canvas elipsy pomocí z levého horního rohu jako v malování. Elipsy si zapamatujeme v dynamickém poli objektů. Když pak klikneme uvnitř nějaké elipsy pravou myší, elipsa se zvětší. type kruznice=class x1,y1,x2,y2:integer; constructor create(x1,y1,x2,y2:integer); procedure zvetsi; procedure kresli; end; pole=array of kruznice; var a:pole;i,k,b,c,d,e:integer;kreslim:boolean; constructor kruznice.create (x1,y1,x2,y2:integer); begin self.x1:=x1; self.x2:=x2; self.y1:=y1; self.y2:=y2; end; procedure kruznice.kresli; begin form1.Canvas.Ellipse(x1,y1,x2,y2); end; procedure kruznice.zvetsi; begin x1:=x1-5; x2:=x2+5; y1:=y1-5; y2:=y2+5; end; procedure TForm1.FormCreate(Sender: TObject); begin i:=1; setlength(a,i); end;

Page 51: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

51

function urci(var kk:integer;xp,yp:integer):boolean; {je true, je-li bod o souřadnicích xp,yp uvnitr kruznice a[kk]} var i:integer; begin kk:=100; urci:=false; for i:=0 to high(a)-1 do if ((a[i].x1<xp) and (a[i].x2>xp) and (a[i].y1<yp) and (a[i].y2>yp)) then begin urci:=true; kk:=i; end end; procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if button=mbleft then begin b:=x; c:=y; kreslim:=true; canvas.Brush.Style:=bsclear; canvas.pen.style:=pssolid; canvas.Pen.Mode:=pmnot; {Mode urcuje vyslednou barvu nakreslene cary podle toho, jaka byla puvodne.pmNotvysledna hodnota je negace soucasneho obsahu Canvasu} d:=x; e:=y; {budeme malovat novou elipsu} canvas.ellipse(b,c,d,e); end else begin if urci(k,x,y) then begin canvas.pen.mode:=pmnot; a[k].kresli; canvas.pen.mode:=pmnot; a[k].zvetsi; a[k].kresli; end; end; end; procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if kreslim then begin {vymazat minulou elipsu} canvas.ellipse(b,c,d,e); d:=x;e:=y; {namalovat novou elipsu} canvas.ellipse(b,c,d,e); end; end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if button=mbleft then begin kreslim:=false; {vymazat minulou elipsu}

Page 52: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

52

canvas.ellipse(b,c,d,e); canvas.Pen.style:=pssolid; a[i-1]:=kruznice.create(b,c,d,e); a[i-1].kresli; inc(i); setlength(a,i); end; end; Příklad 2. Příklad dovolí kreslit úsečky obvyklým způsobem a dodatečně je upravovat. Program si pamatuje seznam bodů reprezentovaný souřadnicemi x,y a seznam úseček (reprezentovaný čísly bodů tvořících začátek a konec úsečky) Myší lze potom buď nakreslit novou úsečku nebo uchopit a přesunout některý dosavadní krajní bod. type TForm1 = class(TForm) Image1: TImage; procedure Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private { Private declarations } public { Public declarations } procedure NakresliUsecku( i: integer ); {tato procedura pak patri formulari} end; … implementation … const MaxBODY = 100; MaxUsecky = 50; var BODY: array[1..MaxBODY] of TPoint; {TPoint definuje obrazovkový bod, potřebuje unit Types type TPoint = packed record X: Longint; Y: Longint; end;} xBODY: integer; Usecky: array[1..MaxUSECKY] of record zacatek, konec: integer end; xUsecky: integer; function NejblizsiBOD( x,y: integer ): integer; var i: integer; vzd, min, mini: integer; const Epsilon = 10; begin min := 10000; mini := 0; for i := 1 to xBODY do begin vzd := abs(BODY[i].x-x) + abs(BODY[i].y-y);

Page 53: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

53

if vzd < min then begin min := vzd; mini := i end end; if min > Epsilon then mini := 0; NejblizsiBOD := mini end; procedure TForm1.NakresliUsecku( i: integer ); begin Image1.Canvas.Pen.mode := pmNot; with BODY[ Usecky[i].zacatek ] do Image1.Canvas.MoveTo( x,y ); with BODY[ Usecky[i].konec ] do Image1.Canvas.LineTo( x,y ); end; var HybuBodem: integer; HybuUseckou: integer; procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var b: integer; i: integer; begin b := NejblizsiBOD( x,y ); if b=0 then { zacinam kreslit novou usecku: } begin Inc( xBODY ); BODY[ xBODY ].x := X; BODY[ xBODY ].y := Y; Inc( xBODY ); BODY[ xBODY ].x := X; BODY[ xBODY ].y := Y; Inc( xUsecky ); Usecky[ xUSECKY ].zacatek := xBODY-1; Usecky[ xUSECKY ].konec := xBODY; HybuBodem := xBODY; HybuUseckou := xUsecky; NakresliUsecku( HybuUseckou ) end else { hybu useckou: } begin HybuBodem := b; for i:= 1 to xUsecky do if (Usecky[ i ].zacatek = HybuBodem) or (Usecky[ i ].konec = HybuBodem) then begin HybuUseckou := i; exit

Page 54: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

54

end end end; procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if HybuBodem = 0 then exit; NakresliUsecku( HybuUseckou ); { smazat minulou usecku } BODY[ HybuBodem ].x := x; BODY[ HybuBodem ].y := y; NakresliUsecku( HybuUseckou ) end; procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin HybuBodem := 0 end; end. Cvičení Vymyslete si vlastní příklad na vektorové kreslení.

17. Tvorba komponent Knihovna vizuálních komponent je navržena tak, aby do ní bylo možno dále přidávat. Zásady:

• Je třeba znát Object Pascal včetně polymorfismu a dědičnosti • Je třeba znát hierarchii VCL • Komponenty by měly být nezávislé • Každá komponenta by měla mít svůj zdroj s jedinečnou ikonou • Všechny alokované zdroje je nutné po skončení práce komponenty uvolnit • Názvy vlastností a událostí jednoduché, logické, anglické • Kód se píše bez grafické podpory

Příklad 1. Vytvoříme komponentu odvozenou od typu TComboBox, která bude obsahovat rozbalovací seznam měsíců. Postup:

• Zavřeme všechny otevřené projekty (File/Close All) • Komponent/New Component

Page 55: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

55

Ancestor type – třída předka Palette Page – lze použít starou (Samples) nebo vytvořit novou Cestu doplní Delphi automaticky.

• Vyplníme údaje a stiskneme OK – průvodce připraví kostru nové komponenty unit Mesice; interface uses SysUtils, Classes, Controls, StdCtrls; type TMesice = class(TComboBox) private { Private declarations } protected { Protected declarations } public { Public declarations } published { Published declarations } end; procedure Register; implementation procedure Register; begin RegisterComponents('New', [TMesice]); end; end. Ve třídě TMesice předefinujeme zděděnou virtuální metodu CreateWnd: TMesice = class(TComboBox) … public procedure CreateWnd; override; … implementation procedure TMesice.CreateWnd; begin inherited Creatwnd; Items.add('Leden'); Items.add('Únor');

Page 56: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

56

Items.add('Bøezen'); Items.add('Duben'); Items.add('Kvìten'); Items.add('Èerven'); Items.add('Èervenec'); Items.add('Srpen'); Items.add('Záøí'); Items.add('Øíjen'); Items.add('Listopad'); Items.add('Prosinec'); ItemIndex:=0; end; Tento kód nemůže být v konstruktoru Create, protože komponenta je kompletně vytvořená až po vykonání všech příkazů konstruktoru. Do té doby nejsou její všechny vlastnosti nastavené a tedy do seznamu nehotové komponenty nelze přidávat hodnoty. Komponenty Delphi jsou shromážděny v balíčcích komponent – zvláštní typ DLL knihoven.

• Instalace komponenty do balíčku Component/Install Komponent Vyberme si nový balíček nebo ji nainstalujeme do již existujícího.

• Po vyplnění všech údajů potvrdíme OK, komponenta se přidá do balíčku V části Contains je seznam komponent v balíčku, v části Requires balíčky potřebné pro fungování komponent (Jinak: nejprve File/new..vytvořit nový balíček a do něj pak přidávat)

• Potvrdíme tlačítko Install, potvrdíme, že chceme balíček překompilovat a naše nová komponenta se

objeví na paletě komponent. Pokud je třeba provést nějaké změny, je třeba balíček znovu překompilovat – tlačítko Compile vlevo nahoře

Příklad 2 – běžící text Nová komponenta bude odvozena od třídy TLabel, navíc bude obsahovat časovač a metody pro modifikaci vlastností. Vlastnosti: Speed – pro rychlost pohybu textu a Active, která spouští a zastavuje pohyb. Předefinujeme konstruktor Create.

Page 57: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

57

unit BLABEL; interface uses SysUtils, Classes, Controls, StdCtrls,ExtCtrls;{kvůli časovači} type TBLABEL = class(TLabel) private { Private declarations } fTimer:TTimer; {nepovinné konvence: identifikátor skrytých atributů začínají písmenem f, metody nastavující vlastnost obsahují set, funkce vracející obsah proměnných get} Aby se podkomponenta Timer zobrazila v inspektoru objektů, je třeba jednak do části Published přidat položku property Timer:TTimer read fTimer ; a v konstruktoru uvést příkazy: ftimer.Name:='casovac'; – pojmenování časovače ftimer.SetSubComponent(true); – zpřístupnění časovače jako subkomponenty v inspektoru objektů procedure posuntext(sender:Tobject); function GetACtive:boolean; procedure setactive(start:boolean); function GetSpeed:cardinal; procedure setspeed(Msec:cardinal); protected { Protected declarations } public { Public declarations } constructor create(AOwner:Tcomponent);override; published { Published declarations } property active:boolean read getactive write setactive; property speed:cardinal read getspeed write setspeed; {aby se timer objevil v OI} property Timer:TTimer read fTimer ; end; procedure Register; implementation procedure Register; begin RegisterComponents('Samples', [TBLABEL]); end; procedure TBLABEL.posuntext(sender:Tobject); var s,pom:string; begin pom:=caption; s:=copy(pom,1,1); delete(pom,1,1); pom:=pom+s; caption:=pom; end; function TBLABEL.GetACtive:boolean; begin result:=ftimer.enabled; end; procedure TBLabel.setactive(start:boolean); begin ftimer.enabled:=start;

Page 58: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

58

end; procedure TBlabel.setspeed(Msec:Cardinal); begin ftimer.interval:=Msec; end; function TBlabel.GetSpeed:cardinal; begin result:=ftimer.interval; end; {abychom mohli používat časovač, je třeba jej vytvořit, proto je nutné předefinovat konstruktor třídy TLabel. Destruktor TTimeru není třeba psát, protože komponenta tuto třídu vlastní a tedy s jejím zrušením dojde i ke zrušení časovače.} Constructor TBlabel.create(AOwner:Tcomponent); begin inherited create(AOwner); ftimer:=TTimer.Create(self); ftimer.Name:='casovac'; ftimer.OnTimer:=posuntext; ftimer.Interval:=500; ftimer.Enabled:=true; ftimer.SetSubComponent(true); end; end. Ikona na paletě komponent: Pokud nepřiřadíme zvláštní ikonu, na paletě se objeví ikona předka, což může být matoucí. V editoru zdrojů (Tools/Image editor) vytvoříme (File/NewComponent Resource File) nový soubor se zdroji komponenty, v něm nakreslíme novou bitmapu 24*24 bodů pojmenovanou stejně jako třída komponenty a velkými písmeny.

(TBLABEL.DCR) Celý soubor se zdroji se pak uloží se stejným názvem jakou jako soubor s definicí komponenty (BLABEL.DCR) na stejné místo kde kde je zdrojový kód komponenty. Komponentu přidáme do vybraného balíčku a nová ikona se objeví na paletě komponent. Pro jistotu je vhodné na začátek zdrojového kódu komponenty připojit direktivu {$R BLABEL.DCR} a balíček s komponentou překompilovat.

Cvičení: Naprogramujte si vlastní komponentu nebo raději dvě.

18. Několik příkladů na závěr

1. Internetové aplikace Delphi obsahují mnoho nástrojů komunikujících s internetem. Patří sem především komponenty Indy – internet direkt – původně opensource, který se stal postupně integrální součástí Delphi. Dají se pomocí nich vytvořit například funkce pro práci s POP3, SMTP, FTP apod. Http klient Vytvoříme snadno pomocí komponenty idHTTP z palety IndyClients (Pro komponentu je podle aktuálního přístupu k internetu někdy třeba nastavit Proxy.Params) Načtení obsahu webové stránky z adresy udané v editačním políčku do Mema: Memo1.text:=IdHTTP1.get(edit1.text) Prohlížeč Stačí komponenta WebBrowser z palety Internet. Zobrazení webové stránky z adresy udané v editačním políčku do této komponenty: WebBrowser1.Navigate(Edit1.text); Pro běžný pohyb v prohlížeči můžeme využít metod této komponenty: Webbrowser1.Refresh Webbrowser1.GoHome Webbrowser1.GoBack Webbrowser1.GoForaward Webbrowser1.Stop

Page 59: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

59

2. Příklad na kombinatorické téma Nalezněte všechna přirozená čísla menší než dané N, jejichž dekadický zápis je tvořený pouze ciframi 2, 3, 5. Varianta 1.: Naprogramujeme logickou funkci, která zjistí, zda číslo obsahuje pouze požadované cifry a otestujeme všechna čísla menší než N. Varianta 2.: (efektivnější) – čísla dané vlastnosti vygenerujeme přímo. Nástin řešení: procedure TForm1.Button2Click(Sender: TObject); {novy člen rady budeme pocitat z predchoziho} var a:array[1..100] of string; i,j,k,n,p:integer; begin n:=spinedit1.Value; a[1]:='2'; a[2]:='3'; a[3]:='5'; i:=3; while StrToInt(a[i])<n do begin inc(i); j:=length(a[i-1]); {delka predchoziho clenu} while (j>0)and (a[i-1][j]='5')do dec(j);{zjistujeme cifru pred koncovymi petkami} if j=0 {nove cislo bude ze samych dvojek} then begin a[i]:=''; for k:=1 to length(a[i-1])+1 do a[i]:=a[i]+'2' ; end else {koncove petky se vymeni na dvojky a cislo pred nimi na naslednika} begin a[i]:=a[i-1]; for k:=j+1 to length(a[i]) do a[i][k]:='2'; if (a[i][j]='2') then a[i][j]:='3' else if (a[i][j]='3') then a[i][j]:='5'; end; end; p:=i-1; {pocet nalezenych cisel} for i:=1 to p do listbox1.Items.Add(a[i]); end;

3. Příklad na práci s velkými čísly Napište program pro přesnou práci s celými čísly většími, než je rozsah, který vymezují Delphi (Sčítání, násobení, faktoriál) Čísla budeme implementovat pomocí polí nebo řetězců. function secti(a,b:string):string; var i,j,k,pom,prenos:integer;vys:string; begin prenos:=0; i:=length(a); j:=length(b); vys:=''; repeat pom:=prenos+Strtoint(a[i])+

Page 60: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

60

Strtoint(b[j]); dec(i); dec(j); vys:=IntToStr(pom mod 10)+vys; prenos:=pom div 10; until (i=0) or (j=0); if (i<>0) or (j<>0) then begin if i=0 then repeat pom:=prenos+strtoint(b[j]); dec(j); vys:=IntToStr(pom mod 10)+vys; prenos:=pom div 10; until j=0 else if j=0 then repeat pom:=prenos+strtoint(a[i]); dec(i); vys:=IntToStr(pom mod 10)+vys; prenos:=pom div 10; until i=0; end; if prenos<>0 then vys:=inttostr(prenos)+vys; secti:=vys; end; function nasobjednocif(cifra,b:string):string; var i,x,pom,prenos:integer;vys:string; begin vys:=''; x:=StrToint(cifra); prenos:=0; for i:=length(b) downto 1 do begin pom:=strtoint(b[i])*x+prenos; vys:=IntToStr(pom mod 10)+vys; prenos:=pom div 10; end; if prenos<>0 then vys:=inttostr(prenos)+vys; nasobjednocif:=vys; end; function nasob(a,b:string):string; var i:integer;pom,nul,vys,s:string; begin vys:='0'; nul:=''; for i:=length(a) downto 1 do begin pom:=nasobjednocif(a[i],B); pom:=pom+nul; vys:=secti(vys,pom); nul:=nul+'0'; end; nasob:=vys; end; function faktor(s:string):string; var i,cislo:integer;fak:string; {predpokladam, ze nebudu pocitat faktorial neceho, co se nevejde do integeru} begin cislo:=strtoint(s);

Page 61: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

61

fak:='1'; for i:=1 to cislo do begin fak:=nasob(fak,inttostr(i)); end; faktor:=fak; end; Jednodušší řešení: procedure TForm1.Button2Click(Sender: TObject); var x,y:string; function secti1(a,b:string):string; {kratsi cislo doplnime nejprve zleva nulami} var i,j,k,p,pom,prenos:integer;vys:string; begin prenos:=0; i:=length(a); j:=length(b); vys:=''; if i>j then for k:=1 to i-j do b:='0'+b else for k:=1 to j-i do a:='0'+a; {ted jsou stejne dlouhe-p} p:=length(a); repeat pom:=prenos+Strtoint(a[p])+ Strtoint(b[p]); dec(p); vys:=IntToStr(pom mod 10)+vys; prenos:=pom div 10; until (p=0); secti1:=vys; if prenos<>0 then vys:=inttostr(prenos)+vys; secti1:=vys; end; function nasob1(a,b:string):string; {nasobeni je opakovane scitani} var i:integer;pom:string; begin pom:='0'; for i:=1 to strtoint(a) do pom:=secti1(pom,b); nasob1:=pom; end; begin x:=edit1.Text; y:=edit2.text; showmessage(secti1(x,y)); showmessage(nasob1(x,y)); end;

4. Úloha na dynamické programování Jsou dány dvě posloupnosti kladných celých čísel A, B, s délkami m, rp. n. Tyto posloupnosti jsou uloženy v polích, jejichž obsah nelze měnit Uvažujme takovou společnou vybranou podposloupnost posloupností A, B, ve které je součet všech jejích členů největší možný. Napište program, který vypíše součet členů takovéto společné vybrané podposloupnosti. Příklad:

Page 62: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

62

m=6, n=7 A=(1,11,2,1,4,99) B=(9,4,1,2,7,1,99) Výstup: 103 (Společné vybrané podposloupnosti s tímto součtem existují dvě (4,99) a (1,2,1,99) Primitivní řešení: postupně generujeme všechny vybrané podposloupnosti z A, pro každou ověříme, zda je také vybranou podposloupností z b a když ano, zjistíme součet. ze součtů udržujeme maximum, které je výsledkem. Závada: příliš velká časová složitost.(exponenciální) (Každá posloupost délky n má 2 na n-tou podposloupností.) Dynamické programování: Obecné principy: Při řešení se postupuje od jednoduššího ke složitějšímu, při řešení složitějších úloh využíváme známé řešení jednodušších. Ai - posloupnost prvních i členů posloupnosti A. (A1,A2,...Ai) Bj - posloupnost prvních i členů posloupnosti B. (B1,B2,...Bj) Obecnější úloha: pro každou dvojici čísel i, j (od nuly do m, případně n)určíme maximální součet prvků společné vybrané podposloupnosti Ai, Bj. Výsledky budeme průběžně ukládat do dvojrozměrné tabulky P[0..m,0..n]. Hodnota P[i,j] vždy představuje řešení úlohy por posloupnosti Ai, Bj. Výsledkem původní úlohy bude tedy hodnota P[m,n], půjdeme od nejmenších hodnot i,j k vyšším a při výpočtu používat výsledky z tabulky P. Tabulku budeme vyplňovat po řádcích, i-tý řádek bude využívat i-1 řádek. Nultý řádek bude obsahovat samé nuly. (Z prázndé posloupnosti nelze nic vybrat) I-tý řádek: P[i,0]=0 P[i,j] vypočítáme na základě známých hodnot P[i-1,j],P[i,j-1], P[i-1,j-1]. Pokud ai<>bj, každá vybraná podposloupnost Ai a Bj je buď vybranou posloupností Ai-1, Bj nebo Bj, Ai-1. P[i,j] je tedy maximum z čísel P[i-1,j] a P[i,j-1]. Pokud ai=bj, jedna z možných vybraných podposloupností Ai, Bj je společná vybraná podposloupnost Ai-1,Bj-1 doplněná o ai. P[i,j] je tedy P[i-1,j-1]+ai. Časová složitost je O(m*n) pro výpočet celé tabulky P. Paměťová rovněž. Vylepšení: Protože každý řádek tabulky P závisí pouze na předchozím řádku, stačí pamatovat si dva řádky, ještě šikovněji vystačíme s jediným polem, kde se střídají hodnoty prvků. Pměťová složitost je zde pouze m+n. (Viz elegantnější řešení) Řešení s maticí: procedure TForm1.Button3Click(Sender: TObject); const max=100;{max.delka posloupnosti} var a,b:array[1..max] of integer; {zkoumane posloupnosti} m,n:integer;{delky posloupnosti a,b} p:array[0..max,0..max] of integer; {tabulka} i:integer;{pocitany radek tabulky} j:integer;{pocitany prvek v radku tabulky} begin m:=strtoint(edit1.text);{pocet prvku A} n:=strtoint(edit2.text); {pocet prvku B} for i:=1 to m do a[i]:=strtoint(memo1.Lines[i-1]); for i:=1 to n do

Page 63: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

63

b[i]:=strtoint(memo3.Lines[i-1]); for j:=0 to n do p[0,j]:=0; {nulty radek tabulky p} for i:=0 to m do p[i,0]:=0; {nulty sloupec tabulky p} for i:=1 to m do for j:=1 to n do {pocitame p[i,j] z i-1teho radku} begin if a[i]=b[j] then p[i,j]:=p[i-1,j-1]+a[i]{nova hodnota p[j]} else if p[i,j-1]>p[i-1,j] then p[i,j]:=p[i,j-1] else p[i,j]:=p[i-1,j] end; showmessage('max soucet spol. vyb. posl:'+inttostr(p[m,n])); end; Elegantnější řešení s jednorozměrným polem: procedure TForm1.Button4Click(Sender: TObject); const max=100;{max.delka posloupnosti} var a,b:array[1..max] of integer; {zkoumane posloupnosti} m,n:integer;{delky posloupnosti a,b} p:array[0..max] of integer; {radek tabulky} Pred:integer;{predchozi hodnota p[i-1,j-1] pri vypoctu p[i,j]} x:integer;{uschovani hodnoty Pred} i:integer;{pocitany radek tabulky} j:integer;{pocitany prvek v radku tabulky} begin m:=strtoint(edit1.text);{pocet prvku A} n:=strtoint(edit2.text); {pocet prvku B} for i:=1 to m do a[i]:=strtoint(memo1.Lines[i-1]); for i:=1 to n do b[i]:=strtoint(memo3.Lines[i-1]); for j:=0 to n do p[j]:=0; {nulty radek tabulky p} for i:=1 to m do begin pred:=0; for j:=1 to n do {pocitame p[j] z i-teho radku} begin x:=p[j];{uschovame aktualni p[j]} if a[i]=b[j] then p[j]:=pred+a[i]{nova hodnota p[j]} else if p[j-1]>p[j] then p[j]:=p[j-1]; pred:=x;{pred pro dalsi prvek} end; end; showmessage('max soucet spol. vyb. posl:'+inttostr(p[n])); end;

Page 64: 1. Zobrazení informací v počítači · 2 Algoritmus převodu desetinných čísel 0,410 = 0,314631463146…8 0,4 * 8 3 2 1 6 4 8 6 4 3 2 Také díky těmto výsledkům je aritmetika

64

Obsah 1. Zobrazení informací v počítači ...................................................................................................................... 1 2. Syntaxe programovacích jazyků, syntaktický analyzátor ................................................................................ 4 3. Úvod do numerických metod ........................................................................................................................ 8 4. Řešení soustavy lineárních rovnic Gaussovou eliminační metodou.............................................................. 12 5. Statistika, modelování náhodných dějů........................................................................................................ 14 6. Multitasking a Delphi.................................................................................................................................. 17 7. Úvod do databází ........................................................................................................................................ 23 8. Vytváření databáze v Paradoxu ................................................................................................................... 27 9. Hodnoty polí............................................................................................................................................... 30 10. Hledání, třídění a filtrování, závislost tabulek ............................................................................................ 33 11. Tvorba vlastní tabulky, pohyb po tabulce a výpočty................................................................................... 36 12. SQL.......................................................................................................................................................... 39 13. Úvod do počítačové grafiky – grafické komponenty .................................................................................. 41 14. Algoritmus kreslení úsečky, animace......................................................................................................... 45 15. Rastrová grafika........................................................................................................................................ 47 16. Vektorová grafika ..................................................................................................................................... 50 17. Tvorba komponent.................................................................................................................................... 54 18. Několik příkladů na závěr ......................................................................................................................... 58 Obsah............................................................................................................................................................. 64


Recommended