Object Pascal - 07: Cyklus for
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Object Pascal - 07: Cyklus forObject Pascal - 07: Cyklus for

 

Object Pascal - 07: Cyklus for

Google       Google       13. 12. 2009       25 592×

Vítejte v sedmém dílu seriálu o jazyku Object Pascal pro začátečníky. V tomto dílu si odpočineme od nových pojmů z OOP (ale to, co už jsme se naučili, budeme používat). Vrátíme k základům programování, tentokrát k cyklu for. Přeji vám pohodu při čtení!

Úvod

Sedmý díl seriálu o jazyku Object Pascal je rozdělen na čtyři kapitoly:

  1. Podíváme se na řešení úloh z minulého dílu.
  2. Stručně si uvedeme cykly v Pascalu.
  3. Důkladněji se budeme zabývat zatím cyklem for.
  4. Nakonec vám nabídnu některé úkoly.

ad 1) Řešení úloh z minulého dílu

Úkol č. 1

Zadání: Zkuste změnit konstruktor ve třídě TKvadrRovnice tak, aby vytvořil rovnici přímo s koeficienty zadanými uživatelem. Provedeme to asi tak, že z hodnot koeficientů uděláme parametry konstruktoru, např. constructor vytvorRovnici(a, b, c: real), a v těle konstruktoru se hodnoty parametrů přiřadí atributům (koeficientům) rovnice, např. self.a := a;. V hlavním programu pak přemístíme příkazy pro zadání hodnot koeficientů uživatelem ještě před vytvoření třídy. Vyvolání konstruktoru by pak mohlo mít tvar vytvorRovnici(a, b, c) - při volání metody se už typ metody (constructor) ani typ parametrů (real) nepíše. Protože o práci s procedurami jsme si zatím řekli velmi málo, bude to pro vás možná těžší úkol.

Řešení: Připojil jsem ještě jeden konstruktor, se třemi parametry a, b, c (vytvorRovnici(a, b, c: real)). Přitom jsem ale ponechal i původní konstruktor bez parametrů se stejným (a původním) názvem (vytvorRovnici). Delphi nabízí jako jiné současné jazyky použití více metod se stejným názvem, lišících se počtem nebo typem parametrů. Říká se tomu přetěžování metod, a protože je zde pro přetížení dobrá příležitost, už jsem ho použil. Všimněte si, že přetížení musíme překladači oznámit, a to slovem overload. Uvede se ale jen v hlavičce obou (či více) přetížených metod, ne už u jejich implementace.

Výpis části kódu jednotky s třídou by mohl být takový (většinu už známe z minulého dílu):

unit U_TKvadrRovnice;

interface
  
// sem by prisla cast uses  
  
type  
//**** definice tridy pro resení kvadratické rovnice
  TKvadrRovnice = class  
    private  
      a: real;  
      b: real;  
      c: real;  
      x1: real;  
      x2: real;  
      pocetKorenu: integer;  
      procedure najdiKoreny();  
    public  
      constructor vytvorRovnici(); overload;
      constructor vytvorRovnici(a, b, c: real); overload;
      procedure zadejKoeficienty(a, b, c: real);
      function vratKoefA(): real;  
      function vratKoefB(): real;  
      function vratKoefC(): real;  
      function vratPocetKorenu(): integer;  
      function vratKorenX1(): real;  
      function vratKorenX2(): real;  
  end;  
//**** konec definice tridy, musí následovat jeste definice metod,
// zde ale az v casti implementation  
  
implementation  
  
//**** definice metod ke tride (instancím tridy) TKvadrRovnice
  
//** soukromá metoda najdiKoreny, urci z koeficientu a, b, c koreny rovnice,
  // pokud existují, a urci také pocet korenu a vlozi ho do atributu
  // pocetKorenu dané instance  
procedure TKvadrRovnice.najdiKoreny();  
  // lokální promenne této metody
  var D, odmD: real;  
    x1, x2: real;  
  begin  
    // diskriminant  
    D := self.b * self.b - 4 * self.a * self.c; // slovo "self" je odkazem  
      // na instanci, která práve metodu pouzivá.
      // Není zde nutné, ale doporucuji ho pouzivat
    // urcení poctu korenu a jejich výpocet
    if D > 0  
      then  
        begin // budou dva koreny
          self.pocetKorenu := 2;  
          // pripravíme si odmocninu z D, at se nemusí opakovane pocitat
          odmD := sqrt(D);  
          self.x1 := (-self.b - odmD) / (2 * self.a);  
          self.x2 := (-self.b + odmD) / (2 * self.a);  
        end // zde jeste nekonci podmínený príkaz, nepíseme tedy stredník
      else if D = 0
        then  
          begin // bude jeden koren
            self.pocetKorenu := 1;  
            self.x1 := -self.b / (2 * self.a);  
          end  
        else self.pocetKorenu := 0; // nebude zádný koren  
  end;  
  
//** verejný konstruktor, který vytvorí instanci (kdvadratickou rovnici)  
  // s prednastavenými hodnotami koeficientu napr. a = 1, b = 2, c = 1.  
  // Tato rovnice by mela mít jediný koren x = -1 a muze poslouzit jako  
  // rychlý test programu  
  // Konstruktor také hned rovnici vyresí - urcí pocet korenu a koreny
  // privátní metodou najdiKoreny()
constructor TKvadrRovnice.vytvorRovnici(); // zde uz se overload
  begin                                        // nepise
    self.a := 1;
    self.b := 2;
    self.c := 1;
    self.najdiKoreny;
  end;

// druha verze konstruktoru (pretizena metoda) - s parametry
constructor TKvadrRovnice.vytvorRovnici(a, b, c: real); // zde uz se overload
  begin                                                    // nepise
    self.a := a; // do atributu objektu a, b, c - oznacenych slovem self -
    self.b := b;    // priradi hodnoty zadanych parametru a, b, c
    self.c := c;
    self.najdiKoreny;
  end;
  

Nový konstruktor s parametry bychom hned měli vyzkoušet v hlavním programu. Jednu možnost uvádím, popř. zkopírujte do Delphi a vyzkoušejte.

program P_kvadrRovnice;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  U_TKvadrRovnice in 'U_TKvadrRovnice.pas';

//**** deklarace promenných programu  
var instanceKvadrRov, rov2, rov3: TKvadrRovnice; // promenná pro odkaz na instanci (objekt)
  a, b, c: real; // pomocné promenné pro moznost zadání koeficientu
  
//**** vlastní program  
begin  
writeLn('Program na reseni kvadraticke rovnice, zkouska prace s objekty.');
writeLn; // vynechání rádku ve výpisu

//** První rovnice  
// vytvorení odkazu na novou instanci - objekt - kvadratické rovnice:
instanceKvadrRov := TKvadrRovnice.vytvorRovnici;
// kontrolní výpis koeficientu, zadaných nasím základním konstruktorem
write('Koeficienty prvni rovnice jsou a = ', instanceKvadrRov.vratKoefA:3:3);
  write(', b = ', instanceKvadrRov.vratKoefB:3:3);
  writeLn(', c = ', instanceKvadrRov.vratKoefC:3:3);
writeLn('   Byly zadany v implicintnim konstruktoru.');
// resení rovnice uz probehlo behem volání konstruktoru
// dle hodnoty atributu PocetKorenu se vypísí koreny
if instanceKvadrRov.vratPocetKorenu = 2
  then
    begin
      write('   Rovnice ma dva koreny x1 = ', instanceKvadrRov.vratKorenX1:3:3);
      writeLn(', x2 = ', instanceKvadrRov.vratKorenX2:3:3);
    end
  else
    if instanceKvadrRov.vratPocetKorenu = 1
      then
        writeLn('   Rovnice ma jeden koren x = ', instanceKvadrRov.vratKorenX1:3:3)
      else
        writeLn('   Rovnice nema zadny koren');
instanceKvadrRov.Free; // zruseni objektu (instance) - uvolneni pameti RAM
//** První rovnice - konec reseni

//** Druha rovnice
writeLn; // vynechání rádku ve výpisu
// vytvorení odkazu na novou instanci - objekt - kvadratické rovnice:
rov2 := TKvadrRovnice.vytvorRovnici(2,4,-3); // konstruktor
    // s parametry, zde "natvrdo" zadanymi bez prispeni uzivatele
// kontrolní výpis koeficientu, zadaných nasím základním konstruktorem
write('Koeficienty druhe rovnice jsou a = ', rov2.vratKoefA:3:3);
  write(', b = ', rov2.vratKoefB:3:3);
  writeLn(', c = ', rov2.vratKoefC:3:3);
writeLn('   Byly zadany "natvrdo" v konstruktoru s parametry.');
// resení rovnice uz probehlo behem volání konstruktoru
// dle hodnoty atributu PocetKorenu se vypísí koreny
if rov2.vratPocetKorenu = 2
  then
    begin
      write('   Rovnice ma dva koreny x1 = ', rov2.vratKorenX1:3:3);
      writeLn(', x2 = ', rov2.vratKorenX2:3:3);
    end
  else
    if instanceKvadrRov.vratPocetKorenu = 1
      then
        writeLn('   Rovnice ma jeden koren x = ', rov2.vratKorenX1:3:3)
      else
        writeLn('   Rovnice nema zadny koren');
rov2.Free; // zruseni objektu (instance) - uvolneni pameti RAM
//** Druha rovnice - konec reseni

//** Treti rovnice, tentokrat pomoci noveho objektu tridy TKvadrRovnice.
writeLn; // vynechání rádku ve výpisu
// Vytvoreni noveho objektu konstruktorem
// rov3.vytvorRovnici; POZOR: Casta chyba zacatecnika, chybny zapis konstruktoru
  // protoze objekt rov3 jeste nebyl vytvoren, nemuze jeste volat nejakou metodu
// toto uz by nebylo vhodne: rov3 := TKvadrRovnice.vytvorRovnici;
  // pouzijeme druhy konstruktor s parametry
// Zadání a resení nové rovnice
writeLn('Zadejte koeficienty a, b, c nove rovnice:');
writeLn('   Koeficienty se pouziji jako parametry konstruktoru s parametry.');
write('   a = '); readLn(a);
write('   b = '); readLn(b);
write('   c = '); readLn(c);
rov3 := TKvadrRovnice.vytvorRovnici(a, b, c); // zde uz byly parametry zadane
rov3.zadejKoeficienty(a, b, c);                       // uzivatelem
// resení rovnice uz probehlo behem volání metody zadejKoeficienty(a, b, c)
// dle hodnoty atributu PocetKorenu se vypísí koreny
if rov3.vratPocetKorenu = 2
  then  
    begin  
      write('   Rovnice ma dva koreny x1 = ', rov3.vratKorenX1:3:3);
      writeLn(', x2 = ', rov3.vratKorenX2:3:3);
    end  
  else  
    if rov3.vratPocetKorenu = 1
      then  
        writeLn('   Rovnice ma jeden koren x = ', rov3.vratKorenX1:3:3)
      else  
        writeLn('   Rovnice nema zadny koren');  
// sem by mel prijit jeste jeden prikaz - jaky?  
rov3.Free;
//** Treti rovnice - konec reseni
  
readLn; // pozastaveni vypisu pred zavrenim konzoly  
  
end.

Jak je vidět, část kódu se nám zde třikrát stejně opakuje. To není dobré, měli bychom to odstranit použitím procedury. O tom ale až jindy.

Úkol č. 2

Zadání: Doplňte na vhodné místo programu i druhé použití destruktoru free.

Řešení: šlo o příkazy

rov2.Free;
popř.
rov3.Free;
které jsou už v předchozí ukázce uvedeny.

Úkol č. 3

Zadání: Zkuste si rychle naprogramovat nový projekt na řešení lineární rovnice tak, že k němu vytvoříte jednotku pro řešení lineární rovnice (např. s názvem U_TLinearRovnice, v jednotce bude třída třeba s názvem TLinearRovnice). Opět bychom mohli využít už starší program, ale zkuste to spíš sami.

Řešení: Zde nechám řešení už na vás. Pokud by někdo řešení poslal, rád ho zveřejním.

ad 2) Základní cykly v Pascalu

Úvod

Cykly umožňují opakování jisté části programu: jednoduchého (jednoho) příkazu nebo složeného příkazu (bloku více příkazů). Prakticky žádný program se bez cyklu neobejde (pro opakování se používá také označení iterace).

V Pascalu jsou pro cyklus tři příkazy: cyklus for, cyklus while a cyklus repeat. Cyklus for využijeme, pokud předem známe počet opakování (průchodů cyklem). Zbylé dva cykly použijeme, když předem počet opakování cyklu neznáme.

  • Známe předem počet opakování (cyklus for).
  • Počet opakování předem neznáme, je řízen podmínkou (cykly while, repeat-until). O těch si řekneme až příště.

ad 3) Cyklus for

Je nejjednodušší, ale abychom jej mohli použít, musíme znát předem požadovaný počet průchodů cyklem. Průchody počítá (řídí) k tomu určená proměnná, tzv. řídicí proměnná cyklu. Obvykle ji značíme malými písmeny i, j, k. Této proměnné přiřadíme na začátku počáteční hodnotu a zadáme také hodnotu koncovou. Při každém průchodu cyklem se její hodnota automaticky zvýší o jedničku. To je důležité a příjemné: u ostatních cyklů se o změnu řídící proměnné musíme postarat sami.

Syntaxe (způsob zápisu) cyklu for

Konkrétní příklady:

1. příklad:

for i := 1 to 10 do  // Cyklus obsahuje jediný jednoduchý příkaz writeLn 
   writeLn(i);       // Co cyklus provede? 

2. příklad:

soucet := 0;
for i := 1 to 10 do
   begin	// Cyklus obsahuje víc příkazů,
      soucet := soucet + i;   // které spojíme do 1 složeného příkazu 
      writeLn(‘Pricitam cislo ‘, i); 
   end;
writeLn(‘Součet od 1 do 10 je: ‘‚ soucet); 

Otázka 1: Promyslete, co každý z těchto cyklů provede. (Odpověď je na konci dílu.)

Obecný zápis cyklu for

Cyklus s jednoduchým (jediným) příkazem:

for ridici_promenna_cyklu := dolni_mez to horni_mez do
   jednoduchy_prikaz;

Cyklus se složeným příkazem (skupinou více příkazů):

for ridici_promenna_cyklu := dolni_mez to horni_mez do
   begin
      prikaz_1;
      prikaz_2;
      ...
      prikaz_n;  // za posledním příkazem nemusí být středník, ale pišme jej.
   end;

Jiná varianta cyklu for: hodnota řídicí proměnné může klesat, pak nejdřív napíšeme horní mez, teprve po ní dolní mez a místo klíčového slova to musíme použít downto (na to se snadno zapomene a program pak hlásí chybu). Příklad:

soucet := 0;
for i := 10 downto 1 do
   begin	// Cyklus obsahuje složený příkaz
      soucet := soucet + i;
      writeLn(‘Pricitam cislo ‘, i);
   end;
writeLn(‘ Součet od 10 do 1 je: ‘‚ soucet);

Znázornění cyklu for vývojovým diagramem

Tento grafický způsob zobrazení algoritmů je pro pochopení základních principů jistě užitečný. O vývojových diagramech se píše např. v malém seriálu Jiřího Chytila na Programujte.com, ve 2. dílu se uvádí cykly, ale ne cyklus for.

Možné znázornění cyklu for jsem nakreslil v programu Draw z OpenOffice.

Víme už, že po průchodu cyklem se hodnota řídící proměnné zvýší (popř. u varianty downto sníží) automaticky o jedničku. To jsem v diagramu zdůraznil kroužkem s řídící proměnnou na konci cyklu.

Doporučuji nakreslit si vývojový diagram aspoň k některým z dalších programů (pro znázornění algoritmu, čili myšlenky postupu řešení). Protože jde o grafický způsob zápisu algoritmu, můžeme jistě opustit příkazy Pascalu a psát do značek vývojového diagramu klidně česky.

Úkoly k cyklu for

Úkol 1: napište program, který spočte součet čísel od 1 do 100. (Úloha zadaná kdysi malému Gaussovi ve škole. Ten si s ní ovšem poradil rychle a bez počítače.)

Úkol 2: napište program, který spočte součet čísel od zadané dolní meze do zadané horní meze. Vstupními hodnotami tedy budou dvě celá čísla, výstupní hodnotou jedno číslo - součet.

Úkol 3: napište program, který spočte součin čísel od zadané dolní meze do zadané horní meze. Vstupními hodnotami tedy budou dvě celá čísla, výstupní hodnotou jedno číslo - součin.

Úkol 4: napište program, který spočte součet n čísel posloupnosti, jejíž členy jsou čísla 1, ½, ¼, 1/8, 1/16 atd. Každý další člen posloupnosti je tedy polovinou předchozího. Vstupní hodnotou bude zadané číslo n (počet sčítaných čísel), výstupní hodnotou bude součet prvních n členů této posloupnosti. Jakému číslu se součet pro rostoucí n stále více blíží? Otázka 2: Může být součet nekonečného počtu čísel konečné číslo? (Odpověď je na konci článku).

Úkol 5: napište program, který spočte součet n čísel posloupnosti, jejíž členy jsou čísla 1, -1/3, 1/5, -1/7, 1/9, -1/11 atd. Nakonec tento součet program vynásobí čtyřmi. Vstupní hodnotou bude tedy zadané číslo n, výstupní hodnotou bude čtyřnásobek součtu prvních n členů této posloupnosti. Jakému číslu se výsledek pro rostoucí n stále více blíží?

Úkol 6: napište program, který spočte součet n čísel posloupnosti, jejíž členy jsou čísla 1, -½, 1/3, -¼, 1/5, -1/6 atd. Vstupní hodnotou bude zadané číslo n, výstupní hodnotou bude součet prvních n členů této posloupnosti. Porovnejte s číslem ln(2).

Úkol 7: napište program pro výpočet faktoriálu z čísla n (tedy součinu 1*2*3*...*n).

Je rozumné i v těchto prográmcích na zkoušení cyklu for používat OOP? Zde by asi stačilo psát krátké programy bez tříd a objektů, ideální by ale bylo části kódu, řešící samotný úkol, vkládat do samotné jednotky třeba s názvem U_Soucty.pas, a to jako funkce (function), aby se daly použít opakovaně i v jiných programech (projektech). V části interface by pak byla jen hlavička funkce, jak už to z povídání o jednotkách umíme, jen tentokrát bez definice třídy a tedy také bez specifikátorů přístupu (jako public nebo private). V části implementation pak funkci naprogramujeme - naimplementujeme.

Závěr

Odpovědi na otázky

Otázka 1: Promyslete, co každý z těchto cyklů provede.

Odpověď: První cyklus vypíše čísla od 1 do 10, druhý napíše totéž a přitom spočte jejich součet, který po provedení cyklu vypíše.

Otázka 2: Může být součet nekonečného počtu čísel konečné číslo?

Odpověď: Ač je to překvapivé, sami asi z matematiky víte, že to možné je. Ukazuje se to i v našich programech z tohoto dílu: ať budete zadávat sebevětší počet sčítanců, u příkladů 4, 5 i 6 součet nepřekročí nikdy jisté číslo, ke kterému se stále víc blíží. To je právě součet nekonečného počtu čísel. Vysvětlení je v tom, že čísla ve sčítané posloupnosti se musí dostatečně rychle zmenšovat.

Cyklus for budete jistě často používat. Čím víc programů zkusíte vytvořit, tím líp. Příště si uvedeme řešení některých úloh a budeme pokračovat cyklem while. Přeji vám vše dobré.

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

Hlasování bylo ukončeno    
0 hlasů
Google
autor je středoškolským profesorem matematiky, fyziky a informatiky na Gymnáziu ve Frýdlantu nad Ostravicí.
Web    

Nové články

Obrázek ke článku Stavebnice umělé inteligence 1

Stavebnice umělé inteligence 1

Článek popisuje první část stavebnice umělé inteligence. Obsahuje lineární a plošnou optimalizaci.  Demo verzi je možné použít pro výuku i zájmovou činnost. Profesionální verze je určena pro vývojáře, kteří chtějí integrovat popsané moduly do svých systémů.

Obrázek ke článku Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý