Programovací jazyk Ada: rozšíření příkladu a formátování výstupů

25. 6. 2015
Doba čtení: 5 minut

Sdílet

V minulém dílu jsme vytvořili projekt pro výpočet kořenů kvadratické rovnice (jednoduchou verzi) a vložili jsme do něj příslušný kód. Ukázali jsme si také rozdíly v kódu při (ne)použití překladových jednotek. V dnešním dílu tento příklad rozšíříme a ukážeme si další možnosti formátování výstupů.

Jak již bylo dříve uvedeno, naše procedura vůbec nezahrnuje možnost výpočtu komplexně sdružených kořenů. To je samozřejmě pro obecné využití nejen škoda, ale vlastně to prakticky zabraňuje jejímu rozumnému využití. Proto se pokusíme situaci napravit a vytvořit skutečně obecný balíček pro výpočet kořenů kvadratické rovnice. Začneme tedy jednoduchou změnou v souboru kvadrov.ads. Zde se změní pouze parametry deklarované procedury následovně:

package kvadrov is

procedure Quadra (A, B, C : in  Float; R1, R2, I1, I2 : out Float; Result : out Character);

end kvadrov;

Do parametrů byly přidány dva další pro výstup imaginární části kořenů a byl změněn výstupní parametr pro zobrazení typu výsledku. Zásah do souboru s výpočty (kvadrov.adb) už musel být samozřejmě zásadnější:

with Ada.Numerics.Elementary_Functions; use  Ada.Numerics.Elementary_Functions;

package body kvadrov is

procedure Quadra (A, B, C : in  Float; R1, R2, I1, I2 : out Float; Result : out Character) is
   D, Z : Float;
begin
   D := B**2 - 4.0 * A * C;
   Z := 2.0 * A;
   if D < 0.0 then
      Result := 'K';
      R1 := -B / Z;
      R2 := R1;
      I1 := Sqrt (-D) / Z;
      I2 := -Sqrt (-D) / Z;
   elsif D = 0.0 then
      Result := 'D';
      R1 := -B / Z;
      R2 := R1;
      I1 := 0.0;
      I2 := I1;
   else
      Result := 'R';
      R1 := (-B + Sqrt (D)) / Z;
      R2 := (-B - Sqrt (D)) / Z;
      I1 := 0.0;
      I2 := I1;
   end if;
   end Quadra;

begin

   null;

end kvadrov;

Kromě úpravy hlavičky procedury se změnil i samotný výpočet. Není na něm ale nic světoborného, takže upozorníme jenom na přidání nové proměnné Z := 2.0 * A, aby se předešlo zbytečnému provádění výpočtů (celkem se volá šestkrát). Také je možné si všimnout konstrukce rozhodovací logiky:

if podmínka then

elsif podmínka then

else

end if;

Nakonec změníme soubor solve.adb takto:

with Ada.Text_IO; use Ada.Text_IO;
with kvadrov;

procedure solve is

   r1,r2,i1,i2 :Float;
   vysledek : Character;

begin

   kvadrov.Quadra(1.0,3.0,1.0,r1,r2,i1,i2,vysledek);
   Put_Line("Vysledky reseni: " & vysledek);
   Put_Line("K1 = " & r1'Img & " " & i1'Img & " i");
   Put_Line("K2 = " & r2'Img & " " & i2'Img & " i");

   end solve;

V souboru byly opět přidány pouze proměnné pro imaginární část při volání funkce a také jejich zobrazení ve výsledcích. Nové verze souborů jsou v přílohách solve2.adbkva­drov2.ads a kvadrov2.adb.

Abychom mohli ověřit správnost nejen překladu a spuštění, ale i konečných výsledků, provedeme tři základní výpočty. Každý z nich bude vycházet z jiných vstupních parametrů – koeficientů kvadratické rovnice. Aby to bylo úplně zřejmé, zvolíme sady parametrů tak, aby postupně proběhl výpočet pro všechny tři typy kořenů. Volání procedury tedy proběhne následovně:

kvadrov.Quadra(1.0,3.0,1.0,r1,r2,i1,i2,vysledek);

Vysledky reseni: R
K1 = -3.81966E-01  0.00000E+00 i
K2 = -2.61803E+00  0.00000E+00 i

kvadrov.Quadra(1.0,2.0,1.0,r1,r2,i1,i2,vysledek);

Vysledky reseni: D
K1 = -1.00000E+00  0.00000E+00 i
K2 = -1.00000E+00  0.00000E+00 i

kvadrov.Quadra(1.0,1.0,1.0,r1,r2,i1,i2,vysledek);

Vysledky reseni: K
K1 = -5.00000E-01  8.66025E-01 i
K2 = -5.00000E-01 -8.66025E-01 i

Jak je vidět, výsledky nám procedura vrací a zdá se, že i správně. Proto se můžeme podívat na další možnosti, které nám Ada nabízí a pomocí kterých můžeme celou aplikaci ještě „doladit“. První změnu provedeme ve dvou krocích, a to pouze v souboru solve.adb:

with Ada.Text_IO;                       --1
with Ada.Float_Text_IO;                     --2
with kvadrov;                           --3

procedure solve is                      --4

    package TIO renames Ada.Text_IO;            --5
    package FIO renames Ada.Float_Text_IO;          --6
    package DIO is new Ada.Text_IO.Float_IO(Float);     --7

   r1,r2,i1,i2 :Float;                          --8
   vysledek : Character;                    --9

begin                                   --10

   kvadrov.Quadra(1.0,3.0,1.0,r1,r2,i1,i2,vysledek);        --11
   TIO.Put_Line("Vysledky reseni: " & vysledek);        --12
   TIO.Put_Line("K1 = " & r1'Img & " " & i1'Img & " i");    --13
   TIO.Put_Line("K2 = " & r2'Img & " " & i2'Img & " i");    --14

   end solve;                                       --15
  • v řádku č. 1 zmizel příkaz use, již nebude potřeba
  • v řádku č. 2 naopak přibyl odkaz na knihovnu výstupů čísel s desetinnou čárkou. Jenom pro zajímavost zkuste přeložit takto upravený kód a zjistíte, že překladač hlásí chybu. To způsobuje právě odebrání příkazu use na prvním řádku
  • Na řádcích 5 až 7 přibyly tři úplně nové a zatím neznámé příkazy. Tyto příkazy ukazují možnosti jak přejmenovat nebo odvozovat stávající standardní nebo uživatelské balíčky a používat je v kódu pod uživatelsky definovaným názvem. V našem případě se jedná o rozlišení dvou výstupních knihoven pro textové a numerické hodnoty. Třetí definice s odvozenou knihovnou je pouze pro ilustraci dané možnosti
  • Aby kód fungoval, musíme na řádcích 12 – 14 předřadit knihovnu, ze které se bude následný příkaz volat. Pokud zkusíme překlad nyní, bude vše v pořádku včetně výsledků, ale zatím bez avizované změny formátu

Aby se změna projevila, musíme provést úpravu těchto tří řádků (12 – 14) a změnit jejich kód následovně:

TIO.Put_Line("Vysledky reseni: " & vysledek);           --1

TIO.Put("K1 = " );                          --2
FIO.Put(Item => r1, Fore => 3, Aft => 6, Exp => 0);     --3
TIO.Put(" ");                                           --4
FIO.Put(Item => i1, Fore => 3, Aft => 6, Exp => 0);     --5
TIO.Put(" i");                                          --6

TIO.New_Line;                       --7
TIO.Put("K2 = " );                      --8
DIO.Put(Item => r2, Fore => 3, Aft => 6, Exp => 0);     --9
TIO.Put(" ");                       --10
DIO.Put(Item => i2, Fore => 3, Aft => 6, Exp => 0);     --11
TIO.Put(" i");                                          --12
  • 1. řádek se nijak nezměnil
  • 2. řádek obsahuje pouze označení kořene a je použit příkaz Put kvůli výstupu na jeden řádek
  • 3. řádek obsahuje odkaz na knihovnu pro zobrazení desetinných čísel a jsou v něm také použity 4 nové parametry:
    1. Item – udává proměnnou, jejíž hodnota se má zobrazit, v tomto případě reálná část kořene
    2. Fore – počet číslic před desetinou čárkou
    3. Aft – počet zobrazených desetinných míst
    4. Exp – zobrazení exponentu. Pokud je jako v našem příkladu hodnota nula, exponent se nezobrazí.
  • 4. řádek obsahuje znak mezery mezi reálnou a imaginární částí kořene
  • 5. řádek je stejný se třetím, jenom se zobrazuje imaginární část kořene
  • 6. řádek obsahuje značku imaginární jednotky
  • 7. řádek provádí odřádkování
  • 8. – 12. řádek jsou stejné, jenom používají volání odvozené knihovny DIO

Výsledek překladu a spuštění je zde:

ict ve školství 24

Vysledky reseni: R
K1 =  -0.381966   0.000000 i
K2 =  -2.618034   0.000000 i

Jak je vidět, formát se změnil a je pro daný příklad mnohem přehlednější, než byl ten původní. Se všemi hodnotami parametrů kromě Item je možné experimentovat a pozorovat jejich vliv na zobrazení výsledků.

V dnešním dílu jsme rozšířili minulý příklad i na komplexní kořeny. V příštím dílu se ještě krátce podíváme na formátování čísel. Také si ukážeme novou vlastnost jazyka Ada – zpracování výjimek. Zaměříme se další vývojové prostředí – Eclipse s příslušným pluginem.

Autor článku