VYSOKÉ UČENÍ TECHNICKÉ V BRNĚ FAKULTA STAVEBNÍ INFORMATIKA II MODUL 01 ALGORITMIZACE A PROGRAMOVÁNÍ V INŽENÝRSKÝCH ÚLOHÁCH STUDIJNÍ OPORY PRO STUDIJNÍ PROGRAMY S KOMBINOVANOU FORMOU STUDIA
Informatika II Modul 01 Algoritmizace a programování Jiří Macur, Miroslav Menšík, Tomáš Apeltauer
Obsah OBSAH OBSAH 3 VSTUPNÍ INFORMACE K MODULU 5 Cíle 5 Požadované znalosti 5 Doba potřebná ke studiu 5 Klíčová slova 5 Použitá terminologie 5 Metodický návod na práci s textem 5 1 ÚVOD 7 1.1 Souvislost programování s ději v počítači 8 1.2 Výběr programovacího jazyka 10 1.3 Vývojové prostředí 10 2 PRÁCE VE VÝVOJOVÉM PROSTŘEDÍ 12 2.1 Moduly 13 3 ZÁKLADNÍ PRVKY PROGRAMU 16 3.1 Proměnné 16 3.1.1 Reprezentace dat 17 3.1.2 Deklarace 18 3.1.3 Identifikátory proměnných 19 3.2 Přiřazovací příkaz 20 3.2.1 Výrazy 20 3.2.2 Jednoduchý vstup a výstup 21 3.3 Podmíněný příkaz 23 3.4 Cyklus 25 3.5 Podprogramy 29 3.5.1 Předávání informací mezi programem a podprogramem 30 3.5.1.1 Globální proměnné 30 3.5.1.2 Vstupní parametry (předávané hodnotou) 31 3.5.1.3 Výstupní parametry (předávané odkazem) 32 3.5.2 Typy podprogramů, funkce 33 3.6 Indexovaná proměnná pole 36
Informatika Modul 01 Počítačové a operační systémy 3.6.1 Vícedimenzionální pole 37 3.6.2 Dynamická pole 38 3.7 Vývojové diagramy 40 3.8 Strukturované programování 41 3.9 Práce s řetězci 42 3.9.1 Určení délky řetězce funkce Len 43 3.9.2 Vytvoření podřetězce funkce Left 43 3.9.3 Vytvoření podřetězce funkce Right 43 3.9.4 Obecné určení podřetězce funkce Mid 43 3.9.5 Vyhledání pozice podřetězce funkce InStr 43 3.9.6 Převod řetězce na velká písmena funkce UCase 43 3.9.7 Převod řetězce na malá písmena funkce LCase 44 3.9.8 Nahrazení podřetězce funkce Replace 44 3.9.9 Konverze znaku na jeho kód funkce Asc 44 3.9.10 Konverze kódu na znak funkce Chr 44 3.9.11 Položky řetězce funkce Split 44 3.10 Datový typ Date pro datum a čas 45 3.10.1 Vložení hodnoty typu Date 45 3.10.2 Extrakce částí hodnot typu Date 46 3.10.3 Časové intervaly 46 3.10.4 Systémový čas a datum 46 3.10.5 Výstup hodnoty typu Date 47 3.11 Další vestavěné funkce třída Math 47 3.11.1 Goniometrické funkce 47 3.11.2 Inverzní goniometrické funkce 47 3.11.3 Exponenciálníní funkce 48 3.11.4 Druhá odmocnina 48 3.11.5 Absolutní hodnota 48 3.11.6 Náhodná čísla 48 3.12 Konverzní funkce 48
Vstupní informace k modulu Vstupní informace k modulu Cíle Čtenář by měl získat přehled o základech algoritmizace a programování a jejich uplatnění při řešení inţenýrských úloh. Text je určen pro studenty technicky orientovaných oborů mimo oblast informačních technologií. Požadované znalosti K přečtení a porozumění tomuto textu jsou potřebné základní znalosti z informatiky v rozsahu vyučovaném běţně na středních školách. Doba potřebná ke studiu Je velmi individuální podle znalostí čtenáře. Pro velmi skromné znalosti je uvedená doba cca 30 hodin. Klíčová slova Algoritmizace, programovací jazyk Visual Basic, strukturované programování, objektově orientované programování, objektový model aplikace, knihovny objektů, implementace inţenýrských úloh Použitá terminologie Diskutovaná problematika se rychle vyvíjí, proto je česká terminologie značně neustálená. V textu je většinou uváděna i ekvivalentní anglická terminologie spolu s příslušnými zkratkami. Metodický návod na práci s textem Text je určen zejména pro osvojení základů algoritmického myšlení, získání všeobecné programátorské dovednosti a schopnosti vyuţívat bohatých objektových knihoven v běţně pouţívaných aplikacích. Je třeba si uvědomovat tvořivou podstatu programátorské práce, kdy lze dospět k cíli mnoha různými způsoby. Čtenář by se neměl nechat odradit zdánlivě sloţitou strukturou pouţívaných objektových modelů. Jsou to jenom nástroje a vznikly proto, aby uţivatelům usnadnily ţivot. Jsou koncipovány tak, aby si kaţdý mohl vybrat (většinou relativně chudou) podmnoţinu objektů pro své účely je zapotřebí se orientovat na logické souvislosti a nikoli na encyklopedické znalosti. Text je rozčleněn do tří modulů: - 5 -
Informatika Modul 01 Algoritmizace a programování První modul popisuje základy algoritmizace, programovacího jazyka a programovacích technik. Při řešení příkladů budeme vycházet z metody strukturovaného programování. Druhý modul obsahuje základy objektově orientovaného programování a vyuţití aplikačního rozhraní kancelářských aplikací zejména pro tvorbu vstupů a výstupů. Seznámíme se také s objektovým modelem aplikací. Třetí modul obsahuje vzorové řešené inţenýrské úlohy s vyuţitím nabytých znalostí. - 6 -
Úvod 1 Úvod Učební text je koncipován pro potřeby technicky orientovaných odborníků, kteří však nejsou profesně orientování na výpočetní techniku a programování. Přesto povaţujeme za nezbytné, aby nabyli základní znalosti v této oblasti zejména ze tří důvodů: 1. Algoritmické myšlení nesporně významně rozšiřuje technický obzor studenta. 2. Mnohé moderní aplikace umoţňují při nulových nákladech rozšíření pomocí různých nadstaveb. Student pak můţe tyto moţnosti snadno a efektivně vyuţít, potřebuje k tomu pouze základy algoritmizace a programování není tak odkázán na nákladné sluţby třetích stran. 3. V praxi pak má absolvent lepší přehled o náročnosti softwarových sluţeb, dovede lépe odhadnout moţnosti vyuţití stávajících prostředků a v neposlední řadě můţe pak přesněji stanovovat poţadavky na nákup programátorského díla či sluţeb. Pro neprofesionála bývá určitou bariérou příliš abstraktní rovina programování. Proto se pokusíme vyjít ze snadno pochopitelných souvislostí, které nám odhalí, proč vlastně programování vypadá tak, jak vypadá, a co se při běhu našich programů v počítači děje. Samozřejmě přitom pouţijeme masívní zjednodušení koneckonců programátory zajímá spíše výsledek neţ detaily probíhajících procesů. Začneme proto hrubě zjednodušeným modelem počítače: - 7 -
Informatika Modul 01 Algoritmizace a programování 1.1 Souvislost programování s ději v počítači Základní komponenty našeho modelu tvoří procesor a operační paměť. Obě komponenty spolu oboustranně komunikují: procesor nejenţe poţaduje od operační paměti informace, ale zároveň je tam také ukládá. Abychom pochopili činnost počítače, vyjdeme ze struktury operační paměti. Paměť je rozdělena na posloupnost elementárních informačních buněk pro jednoduchost představovaných v našem modelu bajty. Kaţdá buňka má přiřazenu pevnou adresu. Adresy tvoří souvislý sled celých čísel. Na obsah buněk na jednotlivých adresách lze samozřejmě nahlíţet jako na hodnotu bajtu vyjádřitelnou jako celé číslo (primárně ve dvojkové soustavě). Adresa 00000000 00000001 00000010 00000011 00000100 Obsah 01001011 10000010 01001111 10101011 00001000 Procesor Paměť Obr. 1.1 základní komponenty počítače Adresa buňky je celé číslo a na obsah bajtu lze také pohlíţet jako na celé číslo (v rozsahu 0 255). Přesto jsou oba údaje velmi rozdílné a je důleţité, abychom je nezaměňovali. Procesor v běţícím počítači vykonává neustále instrukční cykly, které lze rozdělit do tří fází: 1. Procesor si vyţádá obsah buňky s danou adresou pošle do paměti adresu. Paměť poskytne poţadovaný obsah pošle procesoru zpět hodnotu buňky na poţadované adrese (tzv. vyvolávací fáze instrukčního cyklu). 2. Procesor povaţuje obdrţený obsah (zjednodušeně bajt) za kód instrukce nějaké elementární činnosti, kterou umí vykonat. Určení toho, co je - 8 -
Studijní prameny vlastně třeba vykonat, procesor nalezne podle obdrţeného kódu v tzv. tabulce instrukcí, která je součástí procesoru (dekódovací fáze instrukčního cyklu). 3. Procesor tuto instrukci vykoná (prováděcí fáze instrukčního cyklu). Poté si procesor si vyţádá z paměti další bajt s bezprostředně následující adresou a celý cyklus se opakuje. Podrobněji jsou popsány instrukční cykly, struktura procesoru a typy instrukcí v modulu BU01_M01. Je zřejmé, ţe výsledkem některých instrukcí je změna obsahu buněk na stanovené adrese. Tyto buňky jsou tedy pouţity pro uchování informací vzniklých za běhu programu obsahují data. Instrukce pracující s daty musí pochopitelně obsahovat i jejich adresu v podobě dodatečné informace. Instrukce tohoto typu jsou tedy uloţeny ve více buňkách první z nich obsahuje kód instrukce a další adresu dat, s nimiţ se má daná operace provést. Přestoţe uvedený princip fungování počítače vypadá značně vzdáleně od běţného programování, ve skutečnosti tomu tak není. Programátor samozřejmě neprogramuje vkládáním kódů instrukcí do paměti, ale vytváří program v podobě sekvence příkazů v programovacím jazyce. Text těchto příkazů pak přeloţí speciální program (překladač, kompilátor) do patřičných kódů instrukcí. Pojmu instrukce v programu odpovídají příkazy. Tak jako jsou v paměti instrukce uloţeny na adresách následujících za sebou, tak i příkazy následují po sobě a jsou vykonávány postupně (sekvenční provádění). Příkaz je kompilátorem přeloţen pochopitelně do většího počtu instrukcí, důleţité je však pouze pořadí konkrétní adresa instrukce (nebo příkazu) je z hlediska programátora nedůleţitá. Poznámka Ve skutečnosti konkrétní adresu instrukce v době programování ani znát nemůţeme operační systém totiţ při spouštění programu umístí kód instrukcí do souvislé oblasti paměti podle toho, "kde je právě místo". Pokud potřebujeme přerušit souvislou sekvenci příkazů tak, aby se vykonaly instrukce z jiné části paměti, pouţijeme mechanizmus podprogramů nezávislých celků, které jsou označeny identifikátorem (názvem). Tento název pak zastupuje adresu, kam bude směřovat instrukce skoku narušující sekvenční vykonávání příkazů uloţených v paměti za sebou. Proti instrukcím představují data podstatně jiný typ informace. Oblast paměti s uloţenými daty se v programovacím jazyce nazývá proměnná. Je zřejmé, ţe k tomu, aby instrukce mohly s daty pracovat, musí vědět, na jaké adrese jsou data uloţena. Tuto adresu v programu zastupuje identifikátor (název) proměnné. Poznámka Opět platí, ţe konkrétní adresa, kde je proměnná uloţena, je pro programátora nepodstatná. Odvolává se na ni pomocí identifikátoru a vztah mezi identifikátorem proměnné a adresou jejího skutečného uloţení je zcela v reţii kompilátoru a operačního systému operační systém umísťuje data do souvislé oblasti paměti podle toho, kam se mu to hodí. Pak je adrese tohoto prostoru přiřazen identifikátor, se kterým pracuje programátor. - 9 -
Informatika Modul 01 Algoritmizace a programování 1.2 Výběr programovacího jazyka Vyšší programovací jazyky lze klasifikovat podle mnoha kritérií, z hlediska svých moţností jsou však dnes v podstatě ekvivalentní. V tomto textu budeme pouţívat jazyk Visual Basic (dále jen VB), který je upravenou verzí jazyka Basic. Pro laické programátory je tento jazyk vhodný svou jednoduchou syntaxí, avšak hlavní výhodou je jeho značné rozšíření a podpora. Mnoho aplikací lze snadno dále rozvíjet pomocí uvedeného jazyka, coţ je jeden z hlavních aspektů, na který se soustředíme v tomto textu. VB je moderní objektově orientovaný jazyk, práce s objekty je v něm zcela přirozená. S programovými objekty budeme pracovat prakticky od začátku, i kdyţ potřebné hlubší vysvětlení dostane čtenář aţ v odpovídajících kapitolách dalšího modulu. Občas bude proto zapotřebí pouţít některé konstrukce jako "černou skříňku", jejíţ logika bude vysvětlena aţ později. Na tuto skutečnost však bude čtenář vţdy předem upozorněn. Různé varianty jazyka VB jsou k dispozici na mnoha platformách. Jazyk lze pouţívat jako skriptovací nástroj při programování aplikačních serverů internetu, jako standardní vyšší programovací jazyk s vlastním prostředím nebo jako součást jiných aplikací, kde je jazyk pouţit k rozšiřování jejich moţností. 1.3 Vývojové prostředí Programy vytváříme pomocí textového editoru. Vytvořený text (sekvence příkazů) je zapotřebí přeloţit do patřičných kódů instrukcí procesoru pomocí speciálního programu (překladače, kompilátoru). Nakonec musíme tyto kódy dostat do operační paměti počítače a zařídit, aby procesor začal vloţenou sekvenci instrukcí vykonávat. Všechny uvedené činnosti mohou být podporovány speciálním programovým vybavením, které nazýváme vývojové prostředí jazyka. Ve fázi vytváření textu programu nám vývojové prostředí nabídne nejen sluţby běţného editoru, ale kontroluje také případné syntaktické chyby, poskytuje kontextovou nápovědu k pouţití různých konstrukcí jazyka a knihoven podprogramů. Na objektové úrovni potom můţe slouţit k analýze struktury pouţívaných programových objektů. Ve vývojovém prostředí pak můţeme program nejen přeloţit, ale i spustit výsledný kód. Vývojové prostředí nabízí také prostředky pro ladění programu (odhalování chyb a sledování, zda program skutečně vykonává to, co programátor předpokládá). Hlavním úkolem ladicích prostředků je trasování programu, tj. pozastavené vykonávání jednotlivých příkazů, kdy lze po kaţdém příkazu zejména sledovat obsah proměnných. Vzhledem k tomu, ţe se tento text orientuje zejména na uplatnění VB v inţenýrských výpočtech, pouţijeme vývojové prostředí dostupné prakticky ve všech produktech firmy Microsoft, ale i jinde prostředí Visual Basic for Applications (VBA). Vybrat si můţeme např. libovolnou kancelářskou aplikaci z balíku MS Office, ale také třeba dostatečně pokročilou verzi produktu Auto- CAD. My pro výpočty pouţijeme nejčastěji "zázemí" tabulkového kalkulátoru MS Excel. - 10 -
Studijní prameny Naše programy budou pracovat v libovolném prostředí, pokud nebudou vyuţívat nástroje aplikace. Např. velmi často pouţijeme listy sešitu Excel pro vstup a výstup dat. V tom případě program nebude funkční, pokud v počítači produkt MS Excel nebude nainstalován. Stejně tak budeme často vyuţívat aplikaci pro automatickou tvorbu grafů, vestavěnou do produktu MS Office. Náš program bude produkovat grafický výstup, avšak na počítači, kde není balík MS Office nainstalován, pracovat nebude. Půjde nám tedy spíše o vyuţití a rozšíření moţností stávajících aplikací, neţ o vytváření komplexních programů, kde musí programátor vytvořit vše, včetně uţivatelského rozhraní. - 11 -
Informatika Modul 01 Algoritmizace a programování 2 Práce ve vývojovém prostředí Vývojové prostředí spouštíme různými způsoby. První cestou je aktivace karty Vývojář (popis platí pro Office 2010) na hlavním pásu karet. Tato karta je v základním nastavení skryta; v takovém případě je nutné kliknout pravým tlačítkem myši na kterýkoliv pás a vybrat poloţku Přizpůsobit pás karet. V dalším kroku zatrhneme v okně Možnosti aplikace Excel volbu Vývojář a potvrdíme. Obr. 2.1 Volba pro přizpůsobení pásu karet, výběr karty Vývojář Obr. 2.2 Vzhled aktivované karty Vývojář Vývojové prostředí poté spouštíme tlačítkem Visual Basic, případně klávesovou zkratkou Alt + F11. Po spuštění prostředí se objeví jeho hlavní okno s několika ukotvenými panely uvnitř. Přesné rozloţení bude záviset především na rozlišení vašeho monitoru - 12 -
Studijní prameny a také na tom, zda otvíráte konkrétní projekt, nebo pouze editor spouštíte například klávesovou zkratkou. Poznámka Vývojové prostředí naštěstí pouţívá angličtinu. Počeštění vývojových produktů je obvykle kontraproduktivní málokdy je vyčerpávající, většinou obsahuje chyby a navíc je pak obtíţné vyhledávání postupů vytvořených programátorskou komunitou celého světa. Editor jazyka Visual Basic byl počeštěn jen v MS Office 97, v novějších verzích zůstal v anglickém provedení včetně nápovědy k programovacímu jazyku. 2.1 Moduly Programy lze vkládat do různých míst aplikace. My budeme pouţívat umístění do tzv. programových modulů, jejichţ hlavní výhoda spočívá v tom, ţe program lze pouţít v rámci celého projektu aplikace. Do sešitu tedy vloţíme nový modul podle obrázku: Obr. 2. 3 Vložení programového modulu Vytvoří se nový modul s implicitním názvem Module1 (viz obr. 2.4), který lze v případě potřeby přejmenovat. Modulů lze tímto postupem vytvořit více a rozčlenit tak vytvořené programy do přehledných kontejnerů. Tuto moţnost však v našich projektech pouţívat nebudeme, málokdy budeme v rámci jednoho projektu pracovat s více neţ jedním algoritmem. Kromě programových modulů lze vytvářet a pouţívat moduly tříd a pojmenované formuláře. Ty budou diskutovány později. Na obrázku 2.4 je vývojové prostředí spuštěno pro úpravu konkrétního velmi jednoduchého algoritmu (bývá určitou tradicí začínajících programátorů spustit jako jejich první kód jednoduchý výpis textu s uvedeným nebo podobným obsahem). - 13 -
Informatika Modul 01 Algoritmizace a programování Obr. 2.4 Vzhled vývojového prostředí V levé polovině okna editoru jsou dva ukotvené panely. První se jmenuje Project, uvnitř kterého najdete seznam všech otevřených sešitů včetně jejich doplňků. Po klepnutí na značku [+] vlevo od názvu některého sešitu se rozevře seznam všech jeho modulů (a dalších prvků, které si představíme později). Modul samotný otevřeme poklepáním na jeho název. Druhý panel v levé části editoru s názvem Properties vyuţijeme především při práci s formuláři. Je-li aktivní některý z modulů, naleznete zde pouze jedinou vlastnost Name, tedy název modulu. Ten je identický s názvem zobrazeným v panelu Project. V panelu Properties můţete název přepsat podle aktuální potřeby. Okna modulů lze zvětšovat, zmenšovat či ukotvit standardním způsobem. Pravým tlačítkem myši v oblasti pruhu nabídek lze vybrat soubory pouţívaných nástrojů. Základní panel nástrojů s názvem Standard je umístěn přímo v horní části obrazovky. Celkem máme v editoru k dispozici čtyři panely nástrojů (Standard, Debug, Edit, UserForm) a jejich zobrazení můţeme měnit také prostřednictvím nabídky View Toolbars. Z hlavní nabídky panelu Standard stojí za zmínku zejména následující skupiny nabídek: Edit důleţité editační příkazy. Jako příklad lze uvést Find pro hledání v textu nebo Replace pro nahrazení nevhodného textu jinou variantou (například pokud potřebujeme změnit některé konkrétní příkazy rozprostřené napříč dlouhým algoritmem). - 14 -
Studijní prameny Debug slovo označuje v programátorské terminologii hledání a odstraňování chyb kódu. Nabídka pro nás začne být uţitečná později. Run zde najdete příkazy pro spuštění, přerušení či ukončení běhu programu. Tools - obsahuje například příkaz Options pro přístup k předvolbám editoru, References pro výběr pouţívaných knihoven podprogramů; prostřednictvím vlastností projektu zde můţeme programy také ochránit heslem nebo digitálně podepsat. - 15 -
Informatika Modul 01 Algoritmizace a programování 3 Základní prvky programu Program se skládá z příkazů, které ve VB zapisujeme tak, ţe na jednom řádku programu je pouze jeden příkaz. Pokud potřebujeme jeden příkaz zapsat na více řádků (většinou pouze z estetických důvodů, neboť řádek můţe být velmi dlouhý), uvedeme za vybraným oddělovacím znakem (viz dále) v příkazu podtrţítko "_" a pokračujeme na dalším řádku. Příkaz tedy nelze rozdělit v libovolném místě. Na jeden řádek lze zapsat také více příkazů oddělených dvojtečkou. Uvedený postup však ztěţuje čitelnost programu, a proto se příliš nepouţívá. Do textu programu lze vkládat také komentáře. Slouţí pouze pro programátora, překladač komentáře ignoruje. Komentář vytvoříme znakem apostrof ( ' ). VB pak text od apostrofu aţ do konce řádku ignoruje. Oddělovací znaky v textu programu (mezera, tabelátor) jsou tak, jako ve všech moderních programovacích jazycích, volné: tam, kde lze zapsat jeden oddělovací znak, můţeme jich vloţit libovolné mnoţství. Totéţ platí pro nový řádek v textu. Tyto znaky tedy pouţíváme pro zpřehlednění programu; z hlediska VB nemají význam. Naše první programy budou začínat klíčovým slovem Sub, za kterým bude následovat název programu (bez diakritiky či mezer), ukončený nyní zatím ještě prázdnou závorkou. Celý algoritmus bude naopak zakončen klíčovým výrazem End Sub. Slovo Sub označuje typ procedury a jeho význam bude vysvětlen později. Jako příklad zahrnující některé uvedené sloţky programu můţeme pouţít náš příklad z obr. 2.4: Sub Hello() 'komentar k programu MsgBox ("Ahoj světe! / Hello World!") End Sub 3.1 Proměnné Pro uchování dat pouţíváme v programech proměnné. Jiţ bylo uvedeno, ţe identifikátor proměnné v podstatě určuje adresu dat v paměti. Abychom s těmito daty mohli efektivně pracovat, potřebujeme však ještě další údaje: 1. Rozsah (velikost) proměnné, tj. kolik místa v paměti je třeba na uloţení dat rezervovat. 2. Způsob, jakým jsou data v paměti počítače reprezentována. Obvykle totiţ nechceme pracovat s bajty a bity, z nichţ jsou data ve skutečnosti sloţena. Dáváme přednost názornějším entitám, jako jsou např. celá a reálná čísla, text sloţený z písmen apod. Takové entity je zapotřebí zakódovat do bitů v paměti přesně dohodnutým způsobem, který nazýváme reprezentace dat. - 16 -
Studijní prameny Obě uvedené vlastnosti jsou sloučeny do jednoho atributu proměnné, tzv. datového typu. Datový typ proměnné tedy určuje, kolik místa (bajtů) je zapotřebí pro uloţení dané proměnné v paměti a jakým způsobem bude obsah proměnné zakódován do jednotlivých bitů. VB nám nabízí mnoho vestavěných datových typů. Pouţívat jich však na začátku budeme jen několik: Název Popis Rozsah hodnot Integer Celé číslo uloţené ve 2 bajtech rozsah moţných hodnot v proměnné tohoto typu je od -32 768 do 32 767. Long Single Double String Celé číslo uloţené ve 4 bajtech Reálné číslo uloţené ve 4 bajtech Reálné číslo s tzv. dvojnásobnou přesností, 8 bajtů Textový řetězec, uloţen v různém počtu bajtů rozsah moţných hodnot v proměnné tohoto typu je od -2 147 483 648 do 2 147 483 647. rozsah od -3,4.10 38 do 3,4.10 38 Pouţívá se pro manipulaci s velmi velkými čísly (aţ řádu 10 308 ) nebo naopak velmi přesnými desetinnými čísly (aţ do řádu 10-15 ). Rozsah aţ 2.10 9 znaků (proměnná délka řetězce) nebo 64 kilobajtů (pevná délka řetězce). Boolean Logická hodnota, 2 bajty Logická hodnota, která proto můţe nabývat pouze stavu True nebo False. Pouţívá se zejména u vyhodnocení podmínek apod. 3.1.1 Reprezentace dat Reprezentaci základních datových typů si přiblíţíme, i kdyţ s ní programátor obvykle nepracuje. Celá čísla Konkrétní reprezentace čísla 7 typu Integer v paměti počítače vypadá např. takto: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 Maximální kladné číslo, které lze do dvou vymezených bajtů uloţit, je zřejmě: 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Nejvyšší bit určuje znaménko čísla (pro kladná čísla musí mít hodnotu 0). Uvedené číslo vyjádřené v desítkové soustavě je: 1.2 0 + 1.2 1 + 1.2 2 + + 1.2 14 = 32 767 Číslo 5 typu Long bude v paměti reprezentováno ve čtyřech po sobě následujících bajtech 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 0 0 0 0 1 0 1-17 -
Informatika Modul 01 Algoritmizace a programování Reálná čísla I reálná čísla musíme uloţit v podobě bitů, postupuje se přitom následovně: Uvaţujme necelé číslo ve dvojkové soustavě, např. 101,1101 = 1.2 2 + 0.2 1 + 1.2 0 + 1.2-1 + 1.2-2 + 0.2-3 +1.2-4 ( = 5,875 decimálně) 1. Nejprve číslo zapíšeme ve tvaru 1,011101.10 10 (desítkově 1,453125.2 2 ), tedy tak, aby celá část dvojkového čísla byla vţdy 1. 2. Pak uloţíme pouze necelou část čísla (tzv. mantisu) zde 011101 a dvojkový exponent zde 10. U typu Single je pro exponent vyčleněn první bajt, další tři tvoří mantisu. Kaţdý z těchto údajů ještě potřebuje jeden bit na znaménko, tj. velikost čísla určená exponentem můţe být pouze v rozmezí 2-128 2 127. Přesnost čísla (minimální rozdíl, o který se mohou dvě čísla lišit) určuje počet bitů mantisy, je tedy 2-23 (cca 10-7 ). U čísel typu Double je na exponent vyčleněno 11 bitů a 53 zbylých bitů (celkem 8 bajtů) na mantisu. Na první pohled můţe vypadat reprezentace a aritmetické operace s takto uloţenými reálnými čísly komplikovaně. Procesory jsou však navrţeny tak, aby všechny základní aritmetické operace s takovou reprezentací zvládaly v jediné instrukci, tedy velmi rychle. Logické proměnné Datový typ pro uloţení logické hodnoty typ Boolean potřebuje ve skutečnosti pouze jeden bit. Zbytek (celkem dva bajty) tedy zůstává nevyuţit. Řetězce Datový typ String (řetězec znaků) obsahuje posloupnost kódů Unicode (kaţdý znak řetězce má přiřazeny dva bajty). Kromě toho je na začátku posloupnosti uloţena délka řetězce. Protoţe proměnná tohoto typu mění svůj rozsah v paměti podle aktuálně uloţeného obsahu a řetězec má vnitřní strukturu (jednotlivé znaky), pouţili tvůrci VB standardní trik: proměnná typu String obsahuje adresu začátku řetězce. Tak můţe obsah proměnné zaujímat v paměti stále stejný prostor, i kdyţ se vlastní délka řetězce mění. 3.1.2 Deklarace Vymezení paměťového prostoru pro uloţení proměnné (spojení její adresy s identifikátorem) musíme provést před prvním pouţitím proměnné tzv. deklaračním příkazem. Sestává z klíčového slova Dim (dimension rozměr), identifikátoru proměnné, klíčového slova As (jako) a názvu datového typu. Příklad: Dim pocet As Integer Dim x As Single Dim x as Double, y as Double Vidíme, ţe proměnné lze uvézt v jedné deklaraci v podobě seznamu (oddělené čárkou). Tímto způsobem lze zkrátit zápis. Bohuţel, zápis Dim x, y as Double - 18 -
Studijní prameny nepracuje tak, jak bychom očekávali proměnná x bude implicitního typu Variant (dnes jiţ nedoporučovaný), pouze proměnná y bude typu Double. Poznámka Současné verze VB ve skutečnosti deklaraci obvykle nevyţadují. Pokud ji však vynecháme, vytvoříme tím zdroj chyb a omylů VB pouţitou proměnnou umístí do paměti podle svých interních pravidel (obvykle jí přiřadí speciální datový typ Variant). Nejnovější verze VB však jiţ vynechání deklarace nebudou připouštět. Deklarace je velmi důleţitá, i kdyţ z hlediska začátečníka "nic nedělá". Připomínáme, ţe tímto příkazem se odehraje hodně věcí: v paměti se vymezí správný prostor pro data, jeho adresa se sváţe s identifikátorem a při kaţdém ukládání dat se pouţije jejich správná reprezentace podle deklarovaného typu. 3.1.3 Identifikátory proměnných Identifikátory (také názvy) proměnných podléhají určitým syntaktickým pravidlům: Lze v nich v podstatě pouţívat pouze kombinaci abecedních znaků a číslic ţádné mezery, tabelátory, čárky, tečky, vykřičníky apod. Neměli bychom pouţívat také znaky s diakritikou (á, é, ţ, apod.). Identifikátor sice můţe obsahovat číslice, ale nikoli na první pozici. Ve formě identifikátoru bychom dále neměli pouţít některé klíčové slovo VB. Velká nebo malá písmena v identifikátorech jsou zaměnitelná dva identifikátory lišící se jen ve velikosti některých písmen označují stejnou proměnnou. Nesprávný identifikátor moje promenna 2radek značka do Správné identifikátory mojepromenna, moje_promenna druhyradek, radek2 znacka _do (do je klíčové slovo VB) Identifikátory jsou sice omezeny na počet znaků (255) příliš dlouhé identifikátory jsou však nevhodné jiţ z toho hlediska, ţe musíme při jejich pouţití hodně psát. Připomínáme, ţe identifikátor slouţí v programovacích jazycích pouze jako jednoznačný symbol zastupující adresu (umístění proměnné) v paměti počítače přesto by měl být volen výstiţně tak, aby programátor z názvu proměnné snadno odhadl, jaká data jsou v ní uloţena. Pátrání po významu proměnné při analýze programu je nepříjemné. - 19 -
Informatika Modul 01 Algoritmizace a programování 3.2 Přiřazovací příkaz Je základním příkazem kaţdého programovacího jazyka. Nastavuje (resp. mění) obsah proměnné. Jako operátor přiřazení je ve VB pouţit znak "=" Dim x as Integer, y As Integer x = 12 y = x + 10 Podle uvedeného příkladu vidíme, ţe přiřazovací příkaz můţe vlevo obsahovat pouze identifikátor proměnné, vpravo však lze umísti nejen přímo zapsanou hodnotu, ale také výraz obsahující identifikátory proměnných, operátory a další konstrukty jazyka. Výraz je vţdy nejdříve vyhodnocen a do proměnné je vloţen výsledek vyhodnocení. Poznámka V ţádném případě nelze chápat přiřazovací příkaz jako rovnici. Vţdy se jedná o operaci vloţení konkrétních dat do paměti! Na místě znaku "=" bychom si spíše měli představovat " ". 3.2.1 Výrazy Jsou kombinací konstant, identifikátorů a aritmetických, resp. logických operátorů. Při jejich uvedení na jakémkoli místě v programu musí být výrazy vţdy jednoznačně vyhodnotitelné tak, aby VB mohl v dané fázi vykonávání programu na místě výrazu pouţít výsledek jeho vyhodnocení. Výrazy nemusí být pouze součástí přiřazovacího příkazu, lze je pouţít prakticky všude, kde se můţe vyskytovat proměnná (samozřejmě s výjimkou deklarace nebo levé strany přiřazení). Zpočátku se budeme zabývat hlavně aritmetickými výrazy, které se neliší od běţných výrazů pouţívaných např. ve vzorcích (formulích) Excelu. Při vyhodnocování výrazů platí běţná priorita operátorů (nejprve se provede násobení a dělení, pak sečítání a odčítání). Operátory stejné priority se vyhodnocují zleva doprava. Změnu priority dosáhneme pomocí závorek: Např. příkaz x1 = -b / 2 * a vloţí do proměnné x1 hodnotu b/2 vynásobenou a, tj. výsledek výrazu na pravé straně je. Příkaz x1 = -b / (2 * a) je totoţný s příkazem x1 = -b / 2 / a, který vloţí do proměnné x1 hodnotu. Poznámka Instrukce procesoru o mnoho více aritmetických operací neţ je sčítání, odčítání, násobení, dělení nenabízejí. Sloţitější výpočty (např. goniometrické nebo transcendentní funkce apod.) je - 20 -
Studijní prameny třeba sestavit z těchto operací, které jsou však prováděny velmi rychle (v jediné instrukci) s daty uloţenými právě v reprezentaci jiţ uvedených číselných datových typů. Ve výrazech se mohou vyskytovat různé konstanty (někdy se nazývají také literály) ve výše uvedeném výrazu je takovým literálem číslice 2. V aritmetických výrazech lze pouţít také funkce (viz dále). Jedná se o podprogramy, jejichţ výsledkem je jediná hodnota, která se pouţije v místě, kde byla funkce uvedena. Funkce mohou mít parametry, které uvedeme v závorkách. Např. příkaz y = r * sin(x) je proveden následovně: 1. je vyhodnocena funkce sinus pro hodnotu obsaţenou v proměnné x 2. výsledek je vynásoben hodnotou proměnné r 3. výsledek je uloţen jako hodnota proměnné y Vytváření funkcí (a podprogramů obecně) bude blíţe pojednáno později, VB však obsahuje řadu vestavěných funkcí, které budeme pouţívat od začátku. Jejich pouţití ve výrazech je však přirozené a neliší se od syntaxe pouţívané např. ve vzorcích Excelu. 3.2.2 Jednoduchý vstup a výstup Programy vytváříme proto, aby podle stanoveného algoritmu vyřešily nějakou úlohu. Přitom pracují s konkrétními daty uloţenými v proměnných. Na začátku programu je zapotřebí určitá data do proměnných vloţit (inicializace), coţ lze zařídit přiřazovacím příkazem. Svým způsobem lze chápat tuto fázi jako nastavování počátečních podmínek algoritmu. Obvykle pouţijeme program vícekrát s různými daty počátečními podmínkami. Není příliš komfortní v takových případech opravit literály v přiřazovacích příkazech a program opakovaně spouštět. VB nabízí několik moţností, jak můţe uţivatel nastavit obsah proměnných za běhu programu. Protoţe jsme zatím problematiku funkcí dostatečně neprozkoumali, uvedeme zde pouze nejjednodušší moţnost vstupu dat voláním vestavěné funkce VB InputBox: Dim n As Integer n = InputBox("Zadej počet:") Uvedený příkaz vytvoří malé okno s výzvou, kam můţe uţivatel vloţit poţadovaný text. V této fázi je program pozastaven a čeká na odeslání vyplněného vstupního pole (obvykle tlačítkem OK apod.): - 21 -
Informatika Modul 01 Algoritmizace a programování Hodnota vloţená do vstupního pole je uloţena do proměnné n. Parametrem funkce je řetězec, který se pouţije jako výzva upozorňující uţivatele programu, jaká data jsou od něj očekávána. Stejný výsledek by měla také sekvence příkazů: Dim n As Integer Dim vyzva As String vyzva = "Zadej počet" n = InputBox(vyzva) tj. text v okně lze v programu dynamicky měnit. Ve skutečnosti je hodnota vrácená funkcí inputbox vţdy textový řetězec (typ String posloupnost znaků) i v případě, ţe vloţíme číslice. Prostředí VB zde před uloţením hodnoty do proměnné n provede automaticky konverzi znakového řetězce "123" do reprezentace čísla typu Integer. Poznámka Zkušený programátor takové skryté procesy raději eliminuje pouţitím konverzní funkce CInt, která zajistí převod na typ Integer explicitně: n = CInt(InputBox(vyzva)) Programátor má pak lepší kontrolu nad během programu a lépe odhalí moţné chyby (např. v případě, ţe uţivatel do vstupního pole zadá nevhodné znaky). Pozorný čtenář si mohl všimnout, ţe uvedená funkce de facto můţe slouţit i pro výstup dat zde například zobrazuje obsah proměnné vyzva. Pro výstup dat (tj. k zobrazení obsahu proměnných) však VB nabízí univerzální funkci msgbox: MsgBox("Počet je: " & n) Parametrem funkce je řetězec, který je zobrazen v malém okně. Pokud má být součástí řetězce obsah nějaké proměnné, je třeba tento obsah spojit s textovým literálem pomocí operátoru & pro spojování řetězců tak, jak je uvedeno v příkladu. V tomto případě je program po zobrazení výstupu rovněţ pozastaven a čeká, dokud uţivatel neaktivuje tlačítko OK. Poznámka Analogicky jako u předcházející poznámky zde VB automaticky provede konverzi celého čísla n na řetězec tak, aby ho mohl spojit s konstantním řetězcem "Počet je: ". Protoţe jen stěţí můţe dojít k nějakému omylu, explicitní konverze MsgBox("Počet je: " & CStr(n)) se zde pouţívá zřídka. Funkce MsgBox také vrací hodnotu, kterou však zatím nepouţijeme (nepřiřadíme ji do ţádné proměnné). Ve skutečnosti lze ve funkci pouţít další paramet- - 22 -
Studijní prameny ry, které způsobí, ţe v okně budou kromě OK zobrazena další tlačítka (Cancel, Yes, No apod.). Funkce tedy vrací číslo tlačítka, které uţivatel aktivoval. 3.3 Podmíněný příkaz Při tvorbě algoritmů potřebujeme příkazy, které jsou provedeny pouze při splnění určitých podmínek. VB nabízí několik typů příkazů tohoto typu, nejběţnější z nich však je: If <podmínka> Then Else End If <příkazy vykonané při platnosti podmínky> <příkazy vykonané při neplatnosti podmínky> <podmínka> zde představuje tzv. logický výraz, tj. takový, který po vyhodnocení obsahuje hodnotu pravda/nepravda (true/false). Takovou hodnotu lze kromě podmíněného příkazu také uloţit do proměnné typu Boolean (viz výše). Logika příkazu je z výše uvedeného zápisu zcela zřejmá (určitě není třeba připomínat překlad anglických slov if pokud, then pak, else jinak, resp. v opačném případě). Část else lze vynechat pak se v případě nesplněné podmínky z podmíněného příkazu nevykoná nic. Příklad: Příkaz If x > 0 Then x = x + 1 Else x = 1 End If If y > max Then max = y End If je ekvivalentní se zkráceným zápisem If y > max Then max = y Zkrácený zápis lze pouţít v případě, ţe je podmíněně vykonáván právě jeden příkaz. Ukončení příkazu End If pak není pouţito. Příklad programu, řešícího kvadratickou rovnici: 1 Sub kvadrovnice() 2 3 ' -- Deklarace proměnných 4 Dim a As Double, b As Double, c As Double, d As Double 5 Dim x1 As Double, x2 As Double, real As Double, imag As Double 6 Dim vystuprovnice As String 7 8 ' -- Načtení proměnných z listu - 23 -
Informatika Modul 01 Algoritmizace a programování 9 a = InputBox("Zadejte koeficient a") 10 b = InputBox("Zadejte koeficient b") 11 c = InputBox("Zadejte koeficient c") 12 13 ' -- Vytvoření řetězce se zadáním rovnice 14 vystuprovnice = "Kořeny rovnice " & a & "x2 + " & b & "x + " & c & " = 0" 15 16 ' -- Výpočet potřebných výrazů 17 d = b * b - 4 * a * c ' diskriminant 18 real = -b / (2 * a) ' reálný člen 19 20 ' -- Výpočet a zobrazení kořenů podle znaménka diskriminantu 21 If d >= 0 Then 22 x1 = real + Math.Sqr(d) / (2 * a) 23 x2 = real - Math.Sqr(d) / (2 * a) 24 MsgBox (vystuprovnice & vbcrlf & "x1: " & x1 & vbcrlf & "x2: " & x2) 25 Else 26 imag = Math.Sqr(-d) / (2 * a) ' imaginární člen 27 MsgBox (vystuprovnice & vbcrlf & "x1: " & real & "+i." & imag & _ 28 vbcrlf & "x2: " & real & "-i." & imag) 29 End If 30 31 End Sub Komentář Do proměnných a, b, c načteme koeficienty rovnice ax 2 +bx+c = 0 (řádky 9 11). Do řetězcové proměnné vystuprovnice zkonstruujeme zápis rovnice pomocí zadaných koeficientů (řádek 14). Pouţijeme ho při výstupu, aby uţivatel viděl, jaká rovnice se vlastně řeší. V proměnné d uloţíme diskriminant d = b 2 4ac (17). Podle jeho hodnoty rozhodujeme (řádek 21), zda vypočteme nebo zobrazíme reálné kořeny nebo zobrazíme komplexní řešení - 24 -
Studijní prameny Pro výpočet odmocniny vyuţijeme vestavěnou matematickou funkci VB s názvem Sqr (square root). Všechny matematické funkce jsou soustředěny v objektu Math, proto musíme při jejich volání pouţít konstrukci s tečkou tak, jak je uvedeno v programu na řádcích 22, 23 a 26. Význam tohoto zápisu bude objasněn v kapitole o objektech. Pro zobrazení výstupního řetězce musíme vhodně spojit nejen obsahy proměnných, ale i speciální znak pro nový řádek vbcrlf, coţ je vestavěná pojmenovaná konstanta VB. 3.4 Cyklus Příkaz cyklu je algoritmická konstrukce pro opakované vykonávání příkazů, dokud je splněna určitá podmínka. Pouţívá se v iteračních výpočtech, při práci s poli (viz dále) apod. VB umoţňuje pouţít cyklus v několika syntaktických variantách, z nichţ nejběţnější je: Do While <podmínka> <příkazy> Loop Syntaxe je zřejmá z anglického překladu pouţitých slov (do while vykonávej pokud, loop smyčka). Podmínka cyklu má stejný význam jako v podmíněném příkazu If. Příkazy v těle cyklu jsou opakovaně vykonávány, přičemţ je před jejich vykonáním vţdy znovu vyhodnocena podmínka. Jakmile není podmínka splněna, příkaz končí a program pokračuje příkazy za ukončovacím slovem Loop. Příkazy v těle cyklu by tedy měly mít na podmínku vliv v opačném případě hrozí nebezpečí nekonečného cyklu. Výjimkou je případ, kdy některý příkaz v těle je vytvořen tak, ţe cyklus násilně ukončí. Častější je pak případ, kdy podmínka souvisí s čekáním na vnější událost (podmínku lze např. vytvořit tak, ţe cyklus probíhá, dokud neuplyne určitý časový interval, nebo dokud uţivatel nestiskne klávesu apod.). Nekonečný cyklus často vede k tomu, ţe program je zapotřebí násilně zastavit pomocí prostředků operačního systému (obvykle také pomůţe kombinace kláves Ctrl Break). Pouţití cyklu demonstrujeme na příkladu programu, který sečítá "nekonečnou" řadu: Budeme na chvíli předpokládat, ţe VB neumí vyčíslit exponenciální funkci a vytvoříme program, který vypočítá pro zadané x hodnotu e x se zadanou přesností: Vyuţijeme známý rozvoj exponenciální funkce do řady Snadno nahlédneme, ţe pro kaţdé dva po sobě následující členy platí: - 25 -
Informatika Modul 01 Algoritmizace a programování Máme tedy předpis, jak snadno z předcházejícího členu vyjádříme další člen řady a implementace programu je jiţ přímočará: 1 Sub expx() 2 3 ' -- deklarace proměnných 4 Dim rada As Double, x As Double, eps As Double, a As Double 5 Dim i As Integer 6 7 ' -- vstup dat 8 x = InputBox("Zadejte argument exponenciální funkce") 9 eps = InputBox("Zadejte přesnost výpočtu (jako malé číslo)") 10 11 ' -- inicializace cyklu 12 a = 1 13 rada = a 14 i = 0 15 16 ' -- vlastní cyklus přidávající další členy 17 Do While a > eps 18 a = a * x / (i + 1) 19 rada = rada + a 20 i = i + 1 21 Loop 22 23 ' -- výstup výsledku 24 MsgBox ("Zadaná přesnost: " & eps & vbcrlf & _ 25 "Moje funkce exp(" & x & "): " & rada & vbcrlf & _ 26 "Math.exp(" & x & "): " & Math.Exp(x)) 27 End Sub Komentář Do proměnné x načteme hodnotu argumentu funkce a do proměnné eps načteme poţadovanou přesnost výpočtu (řádky 8, 9): Do proměnné a ukládáme jednotlivé členy počítané řady. 0-tý člen řady má podle uvedeného rozvoje hodnotu 1. Tuto hodnotu vloţíme také do proměnné rada, kam budeme kumulovat členy řady. Proměnná i obsahuje index členů řady a zpočátku má hodnotu 0. V rámci cyklu počítáme nové členy z předcházejících členů a přičítáme je do proměnné rada. Cyklus ukončíme, jakmile velikost dalšího vypočteného členu klesne pod zadanou přesnost. Do výstupu (viz obrázek) zahrneme potřebné údaje sloučením řetězců s konstantními částmi a obsahem proměnných (všimneme si, ţe vypočítaná a přesná hodnota se liší na desetinném místě podle zadané přesnosti): - 26 -
Studijní prameny V cyklu jsou pouţity standardní konstrukce: řádek 18 vynásobení obsahu proměnné, výsledek uloţen do stejné proměnné řádek 19 přičítání hodnoty k obsahu proměnné řádek 20 přičtení jedničky k obsahu proměnné Uvedené řádky mají jednu společnou vlastnost: do proměnné je vloţen výsledek výrazu, v němţ se objevuje tatáţ proměnná. Začátečníky tato konstrukce někdy mate je třeba si uvědomit časovou posloupnost vykonávání přiřazovacího příkazu: nejprve je vyhodnocen výraz, teprve potom je výsledek vloţen do proměnné. Při vyhodnocení výrazu se tedy pouţije původní hodnota proměnné. Konstrukce výstupního řetězce v příkazu rozděleném na řádky 24 26 vypadá poněkud nepřehledně. Osvojit si způsob spojování konstantních a proměnných částí řetězců je však bezpodmínečně nutné, pouţívá se velmi často. Nicméně později budeme pro vstupy a výstupy pouţívat jiné konstrukce, vyuţívající aplikace, v nichţ naše programy poběţí. Příklad výpočtu goniometrické funkce obdobným způsobem, který není úplně analogický: Rozvoj funkce sinus do nekonečné řady je následující Opět vyuţijeme iterační předpis pro výpočet dalšího členu řady z předcházejícího členu: V implementaci programu ukáţeme, ţe alternující znaménko řady má několik důsledků: 1 Sub sinx() 2 3 ' -- deklarace proměnných 4 Dim rada As Double, x As Double, eps As Double, a As Double 5 Dim i As Integer 6 7 ' -- vstup dat 8 x = InputBox("Zadejte argument funkce sinus") 9 eps = InputBox("Zadejte přesnost výpočtu (jako malé číslo)") 10 11 ' -- inicializace cyklu 12 a = x 13 rada = a 14 i = 1 15-27 -
Informatika Modul 01 Algoritmizace a programování 16 ' -- vlastní cyklus přidávající další členy 17 Do While Math.Abs(a) > eps 18 a = -a * x * x / (2*i) / (2*i + 1) 19 rada = rada + a 20 i = i + 1 21 Loop 22 23 ' -- výstup výsledku 24 MsgBox ("Zadaná přesnost: " & eps & vbcrlf & _ 25 "Moje funkce sin(" & x & "): " & rada & vbcrlf & _ 26 "Math.sin(" & x & "): " & Math.Exp(x)) 27 End Sub Komentář Na řádku 17 musíme v podmínce pouţít absolutní hodnotu členu. Pouţijeme k tomu funkci Abs z modulu Math. Pokud bychom to neučinili, cyklus by skončil hned při druhém členu, neboť ten je záporný, a tudíţ menší neţ zadaná přesnost. Pro relativně malé úhly (zadané samozřejmě v radiánech) program funguje správně: Pro větší úhly je však výsledek tristní: Abychom zjistili, proč je výsledek našeho výpočtu nepřesný, zobrazíme si velikosti členů sečítané řady: Vidíme, ţe kolem 20. členu jejich velikosti divoce kmitají aţ k hodnotám 10 16, avšak výsledná velikost součtu členů musí být samozřejmě v intervalu <-1, 1>. Odečítat obrovská čísla, která se jen nepatrně liší, je v počítači vţdy riskantní - 28 -
Studijní prameny (numericky nestabilní) vlivem i relativně velmi malého zaokrouhlení velkých čísel můţe být jejich rozdíl fatálně nepřesný. Tento problém lze snadno vyřešit, pokud si uvědomíme, ţe uvedená funkce je periodická její hodnota pro velké úhly je stejná jako pro vhodně vybrané úhly z intervalu <0, 2π>. K dispozici máme aritmetickou operaci "modulo", která vypočítá zbytek po celočíselném dělení dvou čísel: x = 7 Mod 3 ' x obsahuje hodnotu 1 x = 5.2 Mod 3.6 ' x obsahuje hodnotu 1.6 Program lze upravit vloţením řádku za řádek 8 (načtení argumentu): x = x Mod (2 * 3.1415926535898) Pak jiţ bude výstup programu správný pro kaţdý vloţený úhel. Poznámka Ludolfovo číslo π objekt Math neobsahuje. Pokud ho v programu často pouţíváme, měli bychom v deklarační části uvést definici konstanty např. takto: Const PI = 3.1415926535898 Vyuţít lze také vestavěnou funkci arkustangens Math.Atn: pi = Math.Atn(1) * 4 Platí totiţ tg(π/4) = 1 3.5 Podprogramy Pokud bychom chtěli výše uvedený příklad pro výpočet goniometrické funkce pouţívat opakovaně, museli bychom mít moţnost: 1. spustit ho z jiných programů 2. nastavit pro něj z jiných programů výchozí úhel, resp. přesnost předat mu výchozí parametry Bod číslo 1 je splněn automaticky ve VB pouţívaném v jiném prostředí (MS Excel) vytváříme pouze podprogramy (klíčové slovo sub je zkratka ze subroutine podprogram). "Volání podprogramu" provádíme pomocí jeho názvu. Z tradičních důvodů můţeme před identifikátor přidat nepovinné klíčové slovo Call (zavolat): Poznámka: - 29 -
Informatika Modul 01 Algoritmizace a programování Příkaz volání podprogramu je přeloţen do instrukce skoku příští instrukce, kterou procesor vykoná, bude na stanovené adrese určené identifikátorem (názvem) podprogramu. Tak jako je název proměnné spojen s adresou dat, tak je název (pod)programu spojen s adresou sekvence instrukcí v paměti. Součástí instrukce skoku je v tomto případě uloţení stávajícího stavu procesoru do tzv. zásobníku (stack speciální místo v paměti). Kaţdý podprogram má stanoven konec příkazem End Sub. V tomto místě se obnoví původní stav procesoru ze zásobníku včetně původní adresy instrukce, takţe procesor pokračuje ve vykonávání instrukcí v místě, které při volání podprogramu opustil. Bod číslo 2 lze splnit více způsoby: 3.5.1 Předávání informací mezi programem a podprogramem Musíme si uvědomit základní fakt v paměti počítače je současně uloţeno mnoţství programů (a podprogramů). Aby si vzájemně neškodily a nedošlo ke zmatkům, operační systém zabezpečuje adresový prostor kaţdého programu tak, ţe instrukce programu nemohou pracovat s adresami mimo tento prostor. Zjednodušeně řečeno, kdyţ jsou vykonávány instrukce podprogramu, mohou pracovat pouze s identifikátory proměnných, deklarovaných v rámci tohoto podprogramu. Proměnné z jiného (pod)programu k dispozici nemají. Ve většině případů však při volání musíme podprogramu nějaké výchozí informace poskytnout jednoduchou moţnost poskytují tzv. globální proměnné. 3.5.1.1 Globální proměnné Globální proměnné jsou deklarované mimo tělo jakéhokoli programu. VB takovou deklaraci umoţňuje takové proměnné jsou pak přístupné z libovolného podprogramu. Volající program tak můţe před voláním podprogramu nastavit obsah globální proměnné a běţící podprogram si tento obsah můţe přečíst: Proměnné deklarované v podprogramech, které jsme dosud pouţívali, se pak samozřejmě nazývají lokální. Uvedený postup předávání informací se pouţívá omezeně a spíše začátečníky. Jeho nevýhodou je nutnost hlídání názvů globálních proměnných, abychom je nepouţili také v lokálních deklaracích takový střet deklarací vede k těţko odhalitelným chybám. Největší problém však tkví v obtíţné údrţbě obsahu globálních proměnných. V prostředí, kde pouţíváme desítky podprogramů - 30 -
Studijní prameny (např. od různých autorů), si nemůţeme být jisti tím, zda obsah globální proměnné nebyl některým podprogramem změněn, nebo zda nebude některým podprogramem globální proměnná pouţita v jiném významu apod. 3.5.1.2 Vstupní parametry (předávané hodnotou) Lepší moţnosti poskytuje mechanizmus předávání parametrů. Za identifikátorem v hlavičce kaţdého podprogramu vyţaduje VB závorky, kam můţeme vloţit deklaraci tzv. parametrů podprogramu. Parametr si můţeme představit jako speciální proměnnou podprogramu, jejíţ obsah nastavuje volající program. Parametr je tak součástí adresního prostoru podprogramu jako kaţdá jiná lokální proměnná. Vše je nejlépe vidět na příkladu definice a pouţití parametru: Proměnná r podprogramu je definovaná v hlavičce v podobě deklarace. Pouze místo klíčového slova Dim je pouţito byval (zkratka by value). Touto zkratkou vyjadřujeme skutečnost, ţe předtím, neţ bude v podprogramu proměnná r pouţita, bude její hodnota (obsah) naplněna volajícím programem. V podprogramu lze pak nakládat s takovým parametrem tak, jako s kaţdou jinou lokální proměnnou. Poznámka Podprogram v tomto případě nemůţe ovlivnit data volajícího programu. V uvedeném podprogramu plochakruhu lze měnit libovolně obsah parametru r, na obsah proměnné polomer v programu mujprogram to ţádný vliv nemá. Je to ostatně zřejmé i z toho, ţe v druhém případě voláme podprogram a na místě parametru stojí literál (není obsahem ţádné proměnné). Na místě parametru lze pouţít také výraz (např. Call plochakruhu(polomer/4). Výraz se nejprve vyhodnotí a jeho výsledek je vloţen do parametru podprogramu. Parametrů můţe být více pak je uvádíme v hlavičce podprogramu v podobě seznamu deklarací oddělených čárkou: - 31 -
Informatika Modul 01 Algoritmizace a programování Pořadí hodnot parametrů ve volajícím programu musí souhlasit s pořadím v definici záhlaví podprogramu. Navíc musí být datový typ uvedený v záhlaví podprogramu kompatibilní s hodnotou vloţenou při volání. Vyţadovaná kompatibilita vkládané hodnoty a datového typu parametru je pochopitelně stejná jako v případě přiřazovacího příkazu (ve skutečnosti se o nic jiného nejedná). 3.5.1.3 Výstupní parametry (předávané odkazem) Aţ dosud naše podprogramy nepředávaly zpět do volajícího programu ţádnou informaci. Často však potřebujeme volající program informovat o výsledku provádění podprogramu. Jinými slovy, potřebujeme pro podprogram nějaký způsob výstupu poskytnutý zpět do programu, který podprogram vyvolal. VB k tomu poskytuje (kromě globálních proměnných) mechanizmus sdílení proměnné volajícího programu s volaným podprogramem. Pokud v záhlaví podprogramu vyměníme u deklarace parametru klíčové slovo byval za byref (z anglického by reference odkazem), bude předání parametru do podprogramu poněkud odlišné: parametr se bude v podprogramu chovat sice stejně jako předtím, bude však umístěn v adresním prostoru volajícího programu. Aby měl uvedený mechanizmus smysl, musíme v programu (při volání podprogramu) na místě takového typu parametru pouţít název lokální proměnné. Nelze pouţít výraz ani literál ve skutečnosti hraje z hlediska volajícího programu tento parametr roli levé strany přiřazovacího příkazu: přiřazení hodnoty do proměnné pak provede podprogram. Jednoduše pochopíme celý mechanizmus v následujícím příkladu: - 32 -
Studijní prameny Proměnná volume ve volajícím programu se při volání podprogramu ztotoţní s parametrem vysledek podprogramu. To, co podprogram do takové proměnné uloţí, se ve volajícím programu projeví jako hodnota proměnné volume. Výstupní parametr se tedy chová tak, jakoby program a podprogram pouţívaly stejnou globální proměnnou, ve volajícím programu však můţe vystupovat pod jiným názvem neţ v podprogramu. Je však pochopitelné, ţe deklarovaný typ takové proměnné by měl být v programu i podprogramu stejný (jedná se o totoţný prostor v paměti). Čtenáře jistě napadne, ţe tak jako počet vstupních, tak i počet výstupních parametrů můţe být libovolný. Poznámka Z uvedeného je pochopitelný název "parametr předávaný odkazem": do podprogramu je předávána adresa proměnné z volajícího programu (odkaz na paměťový prostor, který si podprogram ztotoţní se svou proměnnou parametrem). Samozřejmě lze pouţít výstupní parametr také v roli vstupního. Obsah, kterým program předávanou proměnnou naplní před voláním, je k dispozici i v podprogramu. To je patrně také důvod, proč je tento typ parametru implicitní pokud vynecháme při deklaraci parametru v podprogramu klíčové slovo by, bude automaticky pouţito byref. Parametr předávaný hodnotou lze pouţít pouze pro případ skalárních dat (nedělitelných na další části). Pokud chceme do podprogramu předat pole nebo objekt (viz dále), musíme pouţít předání odkazem i v případě, ţe se jedná o vstupní parametr (podprogram ho nemění). 3.5.2 Typy podprogramů, funkce VB jako většina jazyků rozeznává dva typy podprogramů: proceduru (subroutine) a funkci (function). Zásadní rozdíl mezi oběma typy podprogramů je v tom, ţe funkce obsahuje mechanizmus předání výstupního parametru hodnotou, který u podprogramu typu procedura absentuje. Funkci lze pouţít ve výrazu přirozeným způsobem: na místo, kde je funkce uvedena, je vloţena výsledná hodnota (výstup) funkce. Teprve pak proběhne vyhodnocení ostatních částí výrazu. - 33 -
Informatika Modul 01 Algoritmizace a programování Příklad definice a pouţití funkce: Funkce sinc(x) = sin x / x (často pouţívána v teorii zpracování signálu) je definována všude kromě hodnoty x = 0. V tomto bodě má však funkce limitní hodnotu 1. Definujeme tedy vlastní funkci, která testuje hodnotu parametru a v případě potřeby vrátí sinc(0)=1 (jinak by došlo k chybě dělení nulou). Oproti definici procedury je v hlavičce funkce rozdíl obsahuje deklaraci výstupní (návratové) hodnoty. K identifikátoru funkce zde přistupujeme, jako by to byl název proměnné, u níţ musíme definovat datový typ. Tuto analogii podporuje i nastavení návratové hodnoty: prostým přiřazovací příkazem vloţíme v podprogramu do "proměnné", kterou představuje název funkce, hodnotu. Ta pak bude figurovat v místě volání funkce. Výhody pouţití jsou nesporné funkci lze pouţít v jakémkoli výrazu prakticky tak, jak jsme zvyklí z běţných algebraických zápisů. Kromě jedné návratové hodnoty můţe mít funkce i libovolné mnoţství parametrů předaných hodnotou nebo odkazem se stejným významem a syntaxí, jako jsme uvedli u procedur. Nyní můţeme upravit náš program pro výpočet goniometrické funkce do podoby funkce (pro zajímavost upravíme výpočet tak, aby funkce počítala s úhlem zadaným ve stupních): - 34 -
Studijní prameny Takto definovaná funkce je pak přímo pouţitelná v listu Excelu jako běţná funkce. Můţeme ji ihned pouţít ve všech formulích: - 35 -
Informatika Modul 01 Algoritmizace a programování 3.6 Indexovaná proměnná pole Často musíme řešit úlohu vyţadující velký počet proměnných stejného datového typu. Navíc tvoří tyto proměnné často logicky kompaktní celek (např. mnoţinu naměřených hodnot, poloţky n-rozměrných vektorů, uzly diferenční sítě apod.). Není právě elegantní (a často ani moţné) deklarovat velká mnoţství proměnných, v nichţ jsou uloţeny všechny prvky takových celků. Kaţdý moderní programovací jazyk tedy zavádí proměnné typu pole, kde jednotlivé prvky odlišujeme celočíselným indexem. Všechny prvky přitom musí být stejného datového typu. Ve VB provádíme deklaraci takového typu proměnné např. takto: Dim mereni(100) As Double Za názvem pole je v závorkách uvedeno nejvyšší číslo (index) prvku v poli. V případě uvedené deklarace je nejniţší index implicitně roven nule. Obsahem kaţdého prvku bude reálné číslo v dvojnásobné přesnosti (Double). Naše pole s názvem mereni tedy bude obsahovat 101 prvků s indexem 0 100 (v paměti zabere 808 bajtů). Pokud nám nevyhovuje nulová implicitní hodnota nejniţšího indexu, můţeme pouţít deklaraci typu: Dim hodnoty(1 To 10) As Integer - 36 -
Studijní prameny V této deklaraci jsme explicitně stanovili rozsah indexu za pomoci klíčového slova To. Ve všech případech si musíme osvojit základní pravidlo: při manipulaci s obsahem pole lze pracovat pouze s jednotlivými prvky pole. S polem jako celkem (aţ na několik světlých výjimek, na které vţdy upozorníme) ve VB pracovat nelze. Nelze tedy jediným příkazem vytvořit z pole kopii nebo sečíst dva vektory apod. Vţdy je třeba provést potřebné operace po jednotlivých prvcích. Ve většině případů pouţijeme cyklus typu For Next (tzv. počítaný cyklus). Příklad Vytvoříme pole o 10000 prvcích a naplníme ho náhodnými celými čísly od jedné do šesti: Dim hodkostkou(1 To 10000) As Integer Dim i As Integer For i = 1 To 10000 hodkostkou(i) = Fix(6 * Rnd() + 1) Next i Poznámka Je zřejmé, ţe deklarovat samostatně 10000 proměnných by nebylo moţné. Tímto způsobem jsme vytvořili v paměti velké mnoţství dat, které můţeme např. statisticky analyzovat. Funkce Rnd() vrací náhodné reálné číslo s rovnoměrným rozdělením z polouzavřeného intervalu <0,1). Uvedená konstrukce transformuje tento interval na celá čísla 1 6, přičemţ funkce Fix vrací celočíselnou část desetinného čísla. Proměnná hodkostkou má vnitřní strukturu; skládá se z prvků (v tomto případě celých čísel). Proměnné typu pole patří do třídy strukturovaných proměnných. Proměnné, které vnitřní strukturu nemají, se nazývají skalární. 3.6.1 Vícedimenzionální pole Jazyk VB umoţňuje pracovat i s poli, která mají více neţ jeden index. Syntaxe podléhá přirozeným zvyklostem. Např. matici 3 x 3 můţeme deklarovat takto: Dim A(1 To 3, 1 To 3) As Double Matice A má devět prvků, s nimiţ pracujeme pomocí dvojice indexů: A(3,1) = 7.2 A(1,3) = -A(3,1) V paměti jsou samozřejmě prvky uloţené za sebou, např. po řádcích, organizace data nás však v tomto případě nemusí zajímat. Kaţdopádně obsadí matice v paměti 9*8 = 72 bajtů. Při manipulaci se strukturami typu matice pouţíváme rovněţ počítané cykly, které však musíme vnořit do sebe. Např. příkazy pro transpozici matice mohou vypadat takto: Dim A(1 To 3, 1 To 3) As Double Dim B(1 To 3, 1 To 3) As Double Dim i As Integer, j As Integer - 37 -
Informatika Modul 01 Algoritmizace a programování naplnění matice A ' B bude obsahovat transponovanou matici A For i = 1 to 3 For j = 1 to 3 B(i,j) = A(j,i) Next j Next i Poznámka VB umoţňuje pouţít aţ 60 indexů, coţ je značně nadbytečné mnoţství. V běţných algoritmech se obvykle nesetkáme s vyšším počtem indexů neţ tři (např. transformace tenzorů apod.). V následujícím příkladu uloţíme do matice C výsledek maticového součinu A x B: Dim A(1 To 3, 1 To 3) As Double Dim B(1 To 3, 1 To 3) As Double Dim C(1 To 3, 1 To 3) As Double Dim i As Integer, j As Integer, k As Integer Dim suma As Double naplnění matice A a B ' C bude obsahovat matici A x B For i = 1 to 3 For j = 1 to 3 suma = 0 For k = 1 to 3 suma = suma + A(i,k) * B(k,j) next k Next j Next i Pomocná proměnná suma nám v tomto případě slouţí jako akumulátor mezivýsledků pro skalární součin i-tého řádku matice A a j-tého sloupce matice B. Poznámka Vloţené cykly často představují pro začátečníky značnou bariéru, je proto zapotřebí věnovat uvedeným konstrukcím dostatečnou pozornost. 3.6.2 Dynamická pole Podobně jako jiné programovací jazyky ani VB neumoţňuje přímo deklarovat pole, jehoţ rozsah indexů není před spuštěním programu znám. Nelze tedy pouţít konstrukci: Dim n As Integer n = 100 Dim pole(1 To n) As Double VB potřebuje v době překladu zkrátka vědět, kde v paměti se proměnná vytvoří a kolik místa zabere. Ţe bude při běhu programu do proměnné n přiřazena nějaká hodnota, je pro proces překladu do instrukcí procesoru irelevantní. - 38 -
Studijní prameny Přesto je nastavení velikosti pole aţ v době běhu programu velmi uţitečné a můţe program zjednodušit a zpřehlednit. Ve VB lze naštěstí pouţít následující posloupnost příkazů: Dim n as Integer, polea() As Double n = InputBox("Zadej počet prvků:") ReDim polea(1 To n) Deklarace pole s prázdnými závorkami připraví VB na pouţití proměnné typu pole. Příkaz ReDim pak za běhu programu předimenzuje pole na nový rozsah. Pole, jehoţ rozsah (počet prvků) se stanoví aţ za běhu programu, se nazývá dynamické. Příklad pouţití dynamického pole: Program vygeneruje pole o zadaném počtu prvků, do kaţdého prvku vloţí náhodné reálné číslo z intervalu 0 1. Potom sečte hodnotu všech prvků a zároveň nalezne maximální a minimální hodnotu v poli. Dalším cyklem spočítáme střední kvadratickou odchylku a rozptyl. - 39 -
Informatika Modul 01 Algoritmizace a programování Pozorný čtenář si určitě všiml, ţe druhý cyklus je zbytečný, součet prvků pole a testování minimální a maximální hodnoty lze provádět v těle cyklu pro generování prvků. Na druhé straně pro výpočet směrodatné odchylky potřebujeme další cyklus, protoţe pracujeme s průměrem, který v předcházejícím cyklu ještě neznáme. Poznámka Všimněme si, ţe programátoři jsou při pouţívání proměnných přirozeně skoupí: pro všechny cykly jsme v našem programu pouţili tutéţ proměnnou (čítač) i, proměnnou suma jsme pouţili jak pro střádání prvků pole, tak kvadratických odchylek prvků od průměru. Šetříme tím rozsah pouţité paměti (coţ je v dnešní rozmařilé době poněkud absurdní), zlepšujeme však i přehlednost programu. 3.7 Vývojové diagramy Pro obecné znázornění algoritmu pouţíváme vývojový diagram. Jedná se o mnoţinu symbolů spojených orientovanými úsečkami, které vyjadřují směr postupu při řešení dílčích kroků. Výhoda vývojového diagramu tkví zejména v přehlednosti a univerzálnosti, není závislý na konkrétním programovacím jazyce. Vyjadřuje obecným způsobem to, co posléze implementujeme v programu. V našich úlohách bude vývojový diagram většinou zbytečný, jeho výhody se naplno projeví teprve u sloţitých a rozsáhlých algoritmů. Vývojový diagram je vyţadován ve fázi analýzy profesionálních programových produktů. Klasický vývojový diagram se skládá z následujících druhů symbolů: 1. Startovací a ukončovací symboly Jsou znázorněny pomocí kruhů, oválů či zaoblených obdélníků, obvykle obsahují nápis Start nebo Konec, či podobnou frázi určující začátek a konec procesu. 2. Spojovací úsečky a šipky Šipka směřující z jednoho symbolu a končící u druhého vyjadřuje časovou posloupnost vykonávání algoritmu (řídící tok). 3. Dílčí krok algoritmu Je znázorněn pomocí obdélníku. Obsahuje popis činnosti, kterou je třeba v daném kroku vykonat. Jeho sloţitost můţe být variabilní, obvykle začínáme s komplexním krokem, který se snaţíme postupně dekomponovat aţ na elementární kroky (viz dále). Příklad: načti matici nebo vypočítej síly apod. 4. Podmíněný příkaz Je reprezentován kosočtvercem, pouţívá se tam, kde je zapotřebí rozhodnutí. Má většinou podobu otázky a její odpovědi ve tvaru Ano/Ne nebo Pravda/Nepravda. Ze symbolu podmíněného příkazu vychází dvě a více šipek, kaţdá z šipek obsahuje moţný druh odpovědi na danou otázku. V tomto prvku se diagram větví. 5. Cyklus Je znázorněn pomocí šestiúhelníku. Cyklus probíhá, dokud je jeho podmínka splněna, poté se přejde k dalšímu kroku algoritmu. Cyklus lze dekomponovat - 40 -
Studijní prameny na podmíněný příkaz a dílčí kroky, někdy se do základních symbolů nezařazuje. 6. Spojovací značka Pro její značení se obvykle pouţívá kruh. Pouţívá se tam, kde je třeba spojit více toků procesu do jednoho společného pokračování. V případě, ţe má vývojový diagram vyjádřit následující programovou implementaci algoritmu, pouţíváme také symboly pro: 7. Podprogram Je znázorněn obdélníkem se svislými čarami po stranách. Jiţ víme, ţe podprogramy jsou takové části algoritmu, které se mohou opakovat a mohou být znázorněny samostatným vývojovým diagramem. 8. Vstup/Výstup Pro vyjádření místa vstupu a výstupu dat do/z algoritmu se pouţívá rovnoběţník, v případě uţivatelského vstupu se někdy pouţívá lichoběţník. Příklad: Získej proměnnou X od uţivatele; zobraz proměnnou X. Postupem času byly zavedeny některá další označení a různé modifikace uvedených symbolů; pro pochopení významu vývojových diagramů však nejsou důleţité. 3.8 Strukturované programování Strukturované programování je metodika návrhu algoritmu, která je zaloţena na dvou principech: 1. Sloţitou úlohu rozdělíme na dílčí úkoly, které řešíme samostatně. Tato metoda postupné dekompozice můţe mít iterační charakter. 2. Při návrhu řešení dílčích úloh pouţijeme pouze povolené řídící struktury s jedním vstupem a jedním výstupem. Právě jeden vstup a jeden výstup řídících struktur je velmi důleţitý pro postup podle bodu 1. Z hlediska VB lze pouţívané příkazy pro řízení běhu programu vyjádřit vývojovým diagramem takto: - 41 -