Hlavní navigace

Matematika v příkazové řádce VIII - utilita calc (3)

15. 3. 2006
Doba čtení: 9 minut

Sdílet

V dnešním pokračování seriálu věnovaného matematicky zaměřeným aplikacím provozovaným zejména z příkazového řádku či z textového terminálu pokračujeme v popisu aplikace calc. Budeme se věnovat pokročilejším technikám prováděným v calcu, zejména práci se seznamy a maticemi.

Obsah

1. Seznamy v calcu
2. Funkce určené pro práci se seznamy
3. Matice
4. Funkce určené pro práci s maticemi
5. Obsah dalšího pokračování tohoto seriálu

1. Seznamy v calcu

V předchozím pokračování tohoto seriálu jsme si řekli, že při programování (skriptování) v calcu není zapotřebí definovat typ proměnných, protože ten je odvozen přímo z obsahu proměnné. To však platí, podobně jako v dalších dynamicky typovaných jazycích, pro takzvané primitivní datové typy, za které jsou v calcu považována celá čísla s neomezeným rozsahem, reálná čísla s libovolnou přesností a rozsahem, komplexní čísla a mimo numerické hodnoty i znaky a řetězce. Při vytváření složitějších skriptů by však bylo výhodné číselné či řetězcové hodnoty sdružovat do větších celků, tj. strukturovaných datových typů. Calc pro tyto účely nabízí možnost práce se seznamy, maticemi a objekty. Při popisu těchto strukturovaných datových typů začneme u seznamů, které mají velký význam jak při zpracování numerických hodnot (pro tyto účely můžeme seznamy ztotožnit s vektory), tak i při načítání, zpracování a výstupu dat textových.

Seznam je v calcu chápán jako dynamická datová struktura, tj. jeho obsah se může za běhu programu měnit, což je rozdílné chování od seznamů známých například z programovacího jazyku Lisp, kde byly seznamy chápány funkcionálně jako konstantní objekty, tj. aplikací nějaké funkce na seznam vznikl nový seznam bez modifikace seznamu původního. Pro vytvoření seznamu není k dispozici žádná speciální syntaktická konstrukce (narozdíl od jazyků, jakými jsou Python či Perl), ale je použit konstruktor seznamů představovaný funkcí list(), která může mít libovolný počet parametrů – tyto parametry se po svém vyhodnocení stanou prvky seznamu a funkce list() vrátí seznam jako celek. Obsah seznamu je možné vypsat dvěma způsoby: buď pouze zadáním jména proměnné, do které je seznam přiřazen, nebo pomocí příkazu či funkce print. V níže uvedeném úryvku kódu je ukázáno vytvoření jednoduchého seznamu o pěti prvcích, přiřazení tohoto seznamu do proměnné a a následné vypsání obsahu seznamu na standardní výstup:

a=list(1,2,3,4);
print a;

list (4 elements, 4 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4 

Již jsme se zmínili o tom, že v calcu se seznamy chovají dynamicky, tj. je možné do nich přidávat nebo z nich ubírat prvky. Pro manipulaci s prvky, které se nachází na začátku seznamu, slouží funkce push() a pop(). Pomocí funkce push() se na začátek seznamu vloží další prvek, další prvky jsou přitom odsunuty (fyzické přesouvání prvků v operační paměti se však neprovádí, pouze se změní jejich indexy). Opak tvoří funkce pop(), která jeden prvek ze seznamu vyjme; hodnota vyjmutého prvku přitom tvoří návratovou hodnotu této funkce. Vzhledem k tomu, že se jedná o „normální“ funkce a nikoli metody objektů, musí být jako první parametr předán vlastní seznam, na který má být operace aplikována. Ukázka použití obou zmíněných funkcí, které se ve své podstatě k seznamu chovají jako k zásobníku, je uvedena v dalším příkladu (všimněte si, že poslední volání funkce pop() bylo aplikováno na prázdný seznam, funkce tedy nevrátila žádnou hodnotu):

b=list(1,2,3,4);
print b;

list (4 elements, 4 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4

push(b,0);
print b;

list (5 elements, 4 nonzero):
        [[0]] = 0
        [[1]] = 1
        [[2]] = 2
        [[3]] = 3
        [[4]] = 4

pop(b);
        0
print b;

list (4 elements, 4 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4

pop(b);
        1
pop(b);
        2
pop(b);
        3
pop(b);
        4
pop(b);
print(b);
list (0 elements, 0 nonzero) 

Kromě funkcí push() a pop(), jež se používají k manipulaci se začátkem seznamu, jsou k dispozici i dvě funkce append(), které naopak manipulují s prvky nacházejícími se na konci seznamu. Pomocí funkce append() je možno k seznamu připojit další prvek, funkce remove() odstraní ze seznamu poslední prvek a současně vrátí jeho hodnotu. Pomocí dvojice funkcí push() a remove() je možné seznam používat jako frontu. Ukázka manipulace s koncem seznamu je ukázána na dalším příkladu:

c=list(1,2,3,4);
print c;

list (4 elements, 4 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4

append(c,5);
print c;

list (5 elements, 5 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4
        [[4]] = 5

remove(c);
        5
print c;

list (4 elements, 4 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4

remove(c);
        4
remove(c);
        3
remove(c);
        2
remove(c);
        1
remove(c);
print c;
list (0 elements, 0 nonzero) 

Seznam je v operační paměti uložen po jednotlivých prvcích, které jsou vzájemně svázány dvojicí ukazatelů. Jeden ukazatel ukazuje na předchůdce prvku, druhý ukazatel na svého následovníka. Díky tomu je možné manipulovat i s prvky, které se nacházejí „uvnitř“ seznamu, tj. nikoli nutně na jeho začátku či konci. Vložení prvku kdekoli dovnitř seznamu obstará funkce insert(), která jako svůj první parametr očekává seznam, jako druhý parametr index prvku a třetím parametrem je hodnota vkládaného prvku. Při práci s funkcí insert() si musíme uvědomit, že prvky uložené v seznamu jsou indexovány od nuly. O odstranění libovolného prvku ze seznamu se postará funkce delete(), přičemž index odstraňovaného prvku je předán jako druhý parametr této funkce. Opět následuje jednoduchý příklad použití těchto funkcí:

d=list(1,2,4,5);
insert(d,2,3);
print d;

list (5 elements, 5 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 3
        [[3]] = 4
        [[4]] = 5

delete(d,2);
        3
print d;

list (4 elements, 4 nonzero):
        [[0]] = 1
        [[1]] = 2
        [[2]] = 4
        [[3]] = 5 

V předchozích odstavcích jsem se zmínil o tom, že prvky seznamu jsou indexovány od nuly. To je velmi důležitá informace, protože k prvkům seznamu je možné přistupovat přímo pomocí jejich indexů. Ty se musí zapisovat do dvojitých hranatých závorek, což je malý rozdíl oproti polím a maticím. Na dalším příkladu je ukázána smyčka, která programově vypíše obsah seznamu uloženého v proměnné e. Délka seznamu, tj. počet prvků, je získána pomocí funkce size():

e=list(10,20,30,40);
for (i=0; i<size(e); i++) print e[[i]];
10
20
30
40 

Seznam nemusí obsahovat pouze numerické hodnoty, ale také (mimo jiných typů dat) řetězce. Zejména při zpracování textových dat je možné použít funkce search() pro vyhledání prvku v seznamu podle své hodnoty, rsearch() pro zpětné vyhledávání prvku a sort() pro setřídění prvků. Následuje ukázka použití funkcí search() a sort() na seznam obsahující řetězce, tj. textová data:

psi=list("cindy", "bobes", "zofka", "amy");
search(psi, "bobes");
        1
search(psi, "vorech");
// nic se nevrátilo - prvek nebyl nalezen
sort(psi);

list (4 elements, 4 nonzero):
        [[0]] = "amy"
        [[1]] = "bobes"
        [[2]] = "cindy"
        [[3]] = "zofka" 

2. Funkce určené pro práci se seznamy

V následující tabulce je proveden soupis některých funkcí, které je možné v calcu použít při práci se seznamy.

Funkce calcu
Jméno funkce Význam funkce
list konstruktor seznamu, tato funkce vytvoří seznam, do nějž vloží všechny zadané parametry
print obecný příkaz či funkce, která mj. slouží k výpisu obsahu seznamu
push vložení nového prvku na začátek seznamu
pop vyjmutí prvku, který se nachází na začátku seznamu
append připojení prvku ke konci seznamu
remove odstranění posledního prvku ze seznamu
insert vložení prvku na libovolné místo v seznamu
delete odstranění libovolného prvku ze seznamu
select výběr prvků ze seznamu na základě zadané podmínkové funkce
size tato funkce vrátí počet prvků uložených v seznamu
sort setřídění prvků v seznamu
search vyhledání prvku v seznamu podle své hodnoty; vrací se index prvku nebo prázdná hodnota
rsearch odpovídá funkci search, ale prohledávání začíná od konce seznamu
reverse otočení prvků v seznamu (provádí se změnou ukazatelů, nikoli fyzickým přesunem dat)
copy kopie celého seznamu do seznamu dalšího
count vrací počet prvků ze seznamu, které odpovídají zadané podmínce
sum vrací součet hodnot všech prvků, které se nachází v seznamu

3. Matice

Dalším strukturovaným datovým typem, který je možné v calcu použít, jsou matice. Význam matic je v matematice a na ni navazujících teoretických i aplikovaných disciplínách tak velký, že mnohé matematicky zaměřené aplikace (například známý Matlab či Octave) matice považují za hlavní datový typ a většina operací v nich s maticemi přímo pracuje, a/nebo jako svůj výsledek vrací matice. Podobně jako seznamy, i matice jsou v calcu implementovány jako dynamický datový typ, který může za běhu skriptu měnit svou hodnotu (resp. hodnoty) svých prvků. Matice mohou mít několik dimenzí, v současné verzi je však možné použít maximálně čtyřrozměrné matice, což by však pro většinu použití aplikačních skriptů mělo dostačovat. Jednorozměrná matice se považuje za vektor, který má, narozdíl od vektoru vytvořeného pomocí seznamu, pevnou velikost (délku).

Matice je možné vytvářet několika různými způsoby, nejpoužívanější je však způsob ukázaný na dalším demonstračním příkladu, ve kterém je uvedena ukázka vytvoření dvojdimenzionální matice nazvaná matice1. Jak je z tohoto příkladu patrné, je při vytváření matic použito slovo mat, za nímž následuje jméno matice a počet prvků v každé dimenzi. Inicializaci jednotlivých prvků je možné provést podobným způsobem, jaký je použit v programovacím jazyku C a jeho následovnících – ve složených závorkách jsou zapsány hodnoty prvků, přičemž celkový počet zadaných prvků by měl odpovídat násobku počtu prvků v každé dimenzi (na rozdíl od céčka se však nemusí hodnoty v jednotlivých dimenzích uzavírat do vlastní dvojice složených závorek, protože tato jazyková konstrukce má v calcu poněkud jiný význam). Příkaz print, který jsme používali při práci se seznamy, je možné použít i při práci s maticemi, podobný je i způsob výpisu prvků.

mat matice1[3,3]={1,2,3,4,5,6,7,8,9}
print matice1

mat [3,3] (9 elements, 9 nonzero):
         [0,0] = 1
         [0,1] = 2
         [0,2] = 3
         [1,0] = 4
         [1,1] = 5
         [1,2] = 6
         [2,0] = 7
         [2,1] = 8
         [2,2] = 9 

Jednorozměrný vektor se vytváří následujícím způsobem:

mat vektor[3]={1,2,3}
print vektor

mat [3] (3 elements, 3 nonzero):
         [0] = 1
         [1] = 2
         [2] = 3 

K prvkům matice je možné přistupovat pomocí indexů zapsaných ve dvojitých hranatých závorkách, jednotlivé indexy jsou přitom odděleny čárkou, což přístup k prvkům matice odlišuje od způsobu přístupu k prvkům polí. Vzhledem k důležitosti matic v matematice jsou v calcu dostupné operátory, které pracují přímo s maticemi. Matice se tedy při použití operátorů dostávají na úroveň primitivních datových typů. Mezi operátory, které je možné při práci s maticemi použít, patří:

Operátory
Operátor Význam operátoru
== vrací pravdivostní hodnotu „true“ v případě, že jsou matice ekvivalentní, tj. mají stejnou velikost (resp. tvar) i hodnoty korespondujících prvků
+ součet dvojice matic stejné velikosti (tato operace se provádí prvek po prvku)
 – rozdíl dvojice matic stejné velikosti (tato operace se provádí prvek po prvku)
* (první operand je matice, druhý operand je numerická hodnota) vynásobení prvků matice zadanou numerickou hodnotou
* (první operand je numerická hodnota, druhý operand matice) vynásobení prvků matice zadanou numerickou hodnotou
/ (první operand je matice, druhý operand je numerická hodnota) vydělení prvků matice zadanou numerickou hodnotou
* (oba operandy jsou matice) maticové násobení, při kterém musí být velikosti matic stejné, ale tvar druhé matice je transponovaný (matice je "otočená)

Velmi často používanými operacemi u matic je výpočet determinantu a inversní matice. Determinant matice (ovšem pouze matice čtvercové) je možné získat funkcí det(), inversní čtvercovou matici pomocí funkce inverse(). V následujícím příkladu je ukázka použití těchto funkcí, včetně případu, kdy inversní matici není možné spočítat, protože zdrojová matice má determinant rovný nule (je singulární):

mat matice2[3,3]={3,0,0,0,1,2,4,5,6}
det(matice2)
-12

inverse(matice2)
mat [3,3] (9 elements, 7 nonzero):
           [0,0] = ~0.33333333333333333333
           [0,1] = 0
           [0,2] = 0
           [1,0] = ~-0.66666666666666666667
           [1,1] = -1.5
           [1,2] = 0.5
           [2,0] = ~0.33333333333333333333
           [2,1] = 1.25
           [2,2] = -0.25

mat matice3[3,3]={1,2,3,4,5,6,7,8,9}
print matice2

det(matice3)
         0

inverse(matice3)
Matrix is not invertible 

Pokud jsou výpočty prováděny s vektory, tj. jednodimen­zionálními maticemi, jsou k dispozici dvě užitečné „vektorové“ funkce. První funkcí je dp() (skalární součin, výsledkem je jedna numerická hodnota), druhou funkcí je cp() (vektorový součin, výsledkem je vektor kolmý na oba zadané vektory). Názvy těchto funkcí pochází z anglických výrazů „dot product“ a „cross product“. Následuje ukázka použití těchto vektorových funkcí, včetně obligátního sčítání a odčítání vektorů (plus operace pro násobení prvků uložených ve vektorech):

mat vector1[3]={1,2,3}
mat vector2[3]={7,8,9}

vector1+vector2

mat [3] (3 elements, 3 nonzero):
         [0] = 8
         [1] = 10
         [2] = 12

vector1-vector2

mat [3] (3 elements, 3 nonzero):
         [0] = -6
         [1] = -6
         [2] = -6

vector1*vector2

mat [3] (3 elements, 3 nonzero):
         [0] = 7
         [1] = 16
         [2] = 27

dp(vector1, vector2)
        50

cp(vector1, vector2)

mat [3] (3 elements, 3 nonzero):
         [0] = -6
         [1] = 12
         [2] = -6 

CS24_early

4. Funkce určené pro práci s maticemi

Funkce pro práci s maticemi
Jméno funkce Význam funkce
size tato funkce vrací počet prvků v nejvyšší dimenzi zadané matice
det výpočet determinantu matice
inverse výpočet inversní matice
dp skalární součin dvojice matic, které musí být jednodimenzionální
cp vektorový součin dvojice matic, které musí být jednodimenzionální
sort setřídění prvku v matici
mattrace součet prvků vektoru (jednodimenzionální matice) nebo součet prvků na diagonále 2D matice
mattrans transpozice dvojrozměrné matice
reverse změna pořadí všech prvků v matici
search nalezení prvku o zadané hodnotě

5. Obsah dalšího pokračování tohoto seriálu

Popis aplikace calc se nám dnešní částí rozrostl o jeden díl, ale v příštím pokračování tohoto seriálu se již touto aplikací budeme zabývat naposled. Popíšeme se práci s uživatelsky definovanými objekty, formátování výstupu a také vstupně/výstupní operace, včetně manipulace se soubory.

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.