pátek 2. února 2018

UDP01 - Úvod do programování

Co je to programování?

Programování je když ... eee ...

Jste na tom až takhle? Tak to je ten správný článek pro vás. Programování je automatizované ovládání počítače a podobných věcí, které mají procesor. Programování je vytváření programu. Program je předpis, kterým se počítač, resp. jeho procesor(y) řídí. Program má kódovanou podobu, proto se mu také říká kód.

Je docela užitečné vědět jak počítač funguje, když ho chceme programovat. Čím lépe rozumíme hardware počítače, tím lépe můžeme programovat. Python je jazyk vysoké úrovně a nevyžaduje hlubokou znalost počítače. Přesto si je řekneme, protože to pomáhá programování pochopit.

Co je to počítač

Počítač si můžeme zjednodušeně rozdělit na 4 funkční části.
  1. vstupní zařízení - klávesnice, myš, mikrofon, síťové připojení, disk, ...
  2. procesor
  3. operační paměť (v podstatě také vstupní/výstupní zařízení)
  4. výstupní zařízení - monitor, reproduktory, síťové připojení, disk, ...

Procesor

Centrem počítače je procesor. Procesor je extrémně složitá součástka velká pár centimetrů a někdy ani to ne. Je to složitý logický obvod, který se skládá z tranzistorů a těch v něm může být přes miliardu. Tahle složitá součástka umí v podstatě jen dvě jednoduché věci, ale zato pekelně rychle. Za prvé umí komunikovat s ostatními částmi počítače a za druhé umí provádět aritmetické a logické operace s čísly. Jediná čísla, které počítače znají jsou čísla 0 a 1, také se uvádí že rozeznávají stav ANO a NE.

Čísla a dvojková soustava

Stav Ano/Ne je to nejmenší možná informace, kterou programátoři nazývá bit. Větší čísla jsou složená z nul a jedniček. Člověk je chytřejší, ten zná čísel deset, 0 až 9. Teprve jedenácté číslo 10 musí složit ze dvou jiných čísel. Tomu se říká desítková soustava. Počítače, protože znají jen dvě čísla, používají dvojkovou neboli binární soustavu. Naše desítková 2 je v počítačštině 10, 3 je 11, 4 je 100 a tak dále. Aby se nepletla naše desítková 10 s binární 10, což jsou různé hodnoty, zapisujeme čísla v binární podobě jako 0b10. A můžeme pak směle psát 2 = 0b10 a nevypadá to divně jako 2 = 10. 

Operační pamět

Operační paměť je součástka, která si umí pamatovat neuvěřitelnou spoustu, miliardy, čísel. Schématicky si ji můžeme představit, jako dvousloupcová tabulku.

Takto vypadá prázdná čtyřbajtová paměť.

AdresaPam. buňka 
00000.0000
10000.0000
20000.0000
30000.0000

V prvním sloupci jsou adresy, v druhém paměťové buňky. Adresy jsou řada čísel 0, 1, 2 ... 1 000 000 000, 1 000 000 001 ... X. Maximální adresa záleží na velikosti paměti. Dříve to byly tisíce, dnes to jsou miliardy. Paměťová buňka si pamatuje 8 jedniček a nul, tedy čísla 0b00000000 až 0b11111111, po našem 0 až 255, což je celkem 256 hodnot. Toto nejmenší uložitelné číslo se jmenuje byte, česky také píšeme bajt, což je lepší, protože to méně svádí plést si bit a byte. 

Pokud si do paměti uložíme číslo 1, vždy spotřebujeme 8 bitů i když nám k tomu stačí jen jeden bit a sedm zbývajících zůstane nevyužito, protože menší počet bitů neumíme adresovat. 

Když naopak budeme chtít do paměti uložit větší číslo než 255, třeba číslo 256 (0b1.0000.0000, ty tečky tam nepatří, dávám je do textu pro lepší přehlednost), pak musíme použít dvě paměťové buňky, tedy 2 byte, tedy 16 bitů. V jedné buňce bude číslo 0b0000.0001 a v druhé 0b0000.0000, po našem 1 a 0 a dohromady to dá 0b0000.0001.0000.0000 což je po našem 256.

Takto to vypadá, když do druhého bajtu (s adresou 1) uložíme hodnotu 15.

AdresaPam. buňka
00000.0000
10000.1111
20000.0000
30000.0000

Pokud neumíte převádět hodnoty z desítkové soustavy do dvojkové a naopak, tak pomůže kalkulačka. V nastavení ji přepněte do vědeckého nebo programátorského režimu a budou v ní k dispozici převody mezi číselnými soustavami.

Takto to vypadá, když od druhého bajtu uložíme hodnotu 3840.

AdresaPam. buňka
00000.0000
10000.1111
20000.0000
30000.0000

Docela zrada, co? Vypadá to stejně jako před tím! Číslo 3840 je binárně 0b0000.1111.0000.0000 a je tedy uloženo ve dvou po sobě následujících bajtech. Z toho vyplývá pro programátory jedna naprosto zásadní věc. Musí vědět nejen na jaké adrese, ale i v kolika bajtech mají číslo uloženo. Pokud tuto informaci ztratí, jsou ztraceni, přestanou být schopni správně pracovat s daty.

Informace v kolika bajtech je číslo uloženo se nazývá datový typ. Datový typ nás informuje nejen o počtu bajtů, ale také o formátu čísla.

Formát čísla

Už víme, že jeden bajt je 8 bitů a do osmi bitů se vleze maximálně 256 hodnot, tedy 0 až 255. To ale vlastně není tak docela pravda. Platí to jen pro kladný (bez-znaménkový) formát čísla.  Jenže my občas potřebujeme používat i záporná čísla.

Proto existuje i znaménkový formát čísla, kde jeden bit (počítáno zleva doprava ten první) představuje znaménko. Když je tento bit = 0, je hodnota kladná. Když je tento bit = 1, je hodnota záporná.

Na hodnotu nám v bajtu potom zůstává 7 bitů, takže takové číslo má rozsah -128 až 127, což je celkem 256 hodnot. 128 hodnot je záporných a 128 hodnot je kladných (nula se považuje za kladnou hodnotu (první bit je nastaven na 0).

Ale pozor, kladná i záporná čísla se počítají od nejmenší hodnoty. Takže neplatí že stejné bity znamenají stejné číslo a liší se jen prvním bitem. Tedy neplatí, že 0b0000.0001 je 1 a 0b1000.0001 je -1. Protože čísla se počítají od nejmenší hodnoty, tak nejmenší kladné číslo 0b0000.0000 je 0 a nejmenší záporné číslo 0b1000.0000 je -128 a 0b1000.0001 je -127. Přehledněji to je vidět v tabulce 1 a 2:

Tabulka 1
oba formáty
bityhodnota
0000.00000
0000.00011
0000.00102
0000.00113
0000.01004
0111.1111127
Tabulka 2
znaménkový formát
bityhodnota
1000.0000-128
1000.0001-127
1000.0010-126
1000.0011-125
1000.0100-124
1111.1111-1
Tabulka 3
kladný formát
bityhodnota
1000.0000128
1000.0001129
1000.0010130
1000.0011131
1000.0100132
1111.1111255


Tabulka 1 nám také ukazuje, že pokud první bit je 0, pak hodnoty jsou u obou formátů stejné.

Tabulka 2 a 3 nám ukazuje, že pokud je první bit 1, pak hodnoty se u obou formátů liší.

Z toho je zřejmé, že programátor musí vědět nejen do kolika bajtů číslo uložil, ale také jaká má formát, protože ty stejné bity mohou jednou znamenat -1 a jednou 255. Jak již bylo řečeno, tyto informace jsou součástí datového typu.

Datové typy

S datovými typy je to složité. Různé programovací jazyky s nimi mohou nakládat různě. A to jak s nimi jazyk zachází je významná vlastnost programovacího jazyka. V podstatě existuji dvě hlavní osy, podle který rozlišujeme jazyk silně a slabě typové a jazyky staticky a dynamicky typované. Jsou možné všechny kombinace. Python je jazyk silně typový s dynamickým typováním.

Tohle si zatím do hloubky vysvětlovat nebudeme, jen si řekneme, že díky tomu se Python snadno používá a v podstatě výše uvedeným informacím o bitech, bytech a formátech čísel nemusíme nic vědět. V Pythonu si můžeme napsat, že a = 10 nebo b = -100000000000 a vůbec se nemusíme zabývat tím, jak je to číslo v paměti uložené, jaký má datový typ nebo jak se číslo převádí z jednoho typu na druhý. Python tohle všechno řeší na pozadí za nás. V některých jiných jazycích tohle musí programátor všechno ovládat a předem deklarovat.

Python jako takový ale datové typy používá a občas může k nějakým typovým konfliktům dojít. Takže i programátor v Pythonu musí o jeho datových typech vědět a umět s nimi pracovat, jen to má trochu jednodušší. Python patří mezi jazyky, kde si programátor může vytvářet i svoje vlastní datové typy a není omezen jen na základní.

A zpátky k procesoru

Procesor komunikuje s pamětí. Načítá z ní čísla do svých registrů nebo naopak je z nich ukládá do paměti. 

Registr je paměťová buňka přímo v procesoru. Každý procesor jich má jen několik málo. Zato jsou obvykle větší a nemají jenom 8 bitů jako ty v paměti. Dnes bývají registry obvykle 64 bitové. Velikost registru je významná  vlastnost procesoru. Pokud se někdo baví o starých osmibitech, nebo že má 32 nebo 64 bitové Windows, baví se právě o této veličině.

Velikost datového registru nám říká, s jak velkým číslem nebo adresou může procesor přímo pracovat. Může pracovat i s většími čísly (protože staré osmibity byly sice hodně omezené, ale přeci jen uměly počítat i s čísly většími než 255). Ale takové počítání je nepřímo, což znamená mnohonásobně pomalejší.

Velikost adresového registru nám říká s jak velkou pamětí procesor umí přímo pracovat. Třeba 32 bitové procesory Pentium uměly pracovat jen s 32 bitovou adresou, tedy s adresami do 4 miliard. To omezovalo velikost operační paměti teoreticky na 4 GB, reálně na 3 GB. Až 64 bitové procesory nám umožnily používat dnes běžných 8 nebo 16 GB operační paměti.

Dnes je velikost registru pro data i pro adresy stejně velká, dříve tomu tak nebývalo.

Velikost registrů je podstatná i pro programy. Definuje jak velké čísla může program používat přímo. Proto máme 32 nebo 64 bitové programy, třeba již zmíněná windows. Nepřekvapí, že 64 bitové procesory mohou spouštět 32 bitové programy (ty se do 64 bitového registru vejdou), ale naopak to nejde. I Python může být 32 nebo 64 bitový.

Procesor a v principu funguje tak, že si zpaměti do registru načte čísla, provede instrukci, která s těmi čísly provede nějakou operaci, výsledek uloží do registru a odtud uloží zase někam do paměti. A tak pořád dokola. Jaká se provede instrukce, to záleží na programátorovi, to je právě ten program. 

Ty instrukce jsou očíslované, takže program je řada čísel, která je rovněž uložena v paměti. Takový program se nazývá strojový kód. Program rozlišuje mezi tím, kde má v paměti program a kde data ale vlastně i program jsou data.

Programovací jazyky

Strojový kód je fajn pro procesor, ale člověk si v tom moc nepočte. Je velmi složité psát program ve strojovém kódu a je jen málo programátorů, kteří to umí a ani oni v tom neumí naprogramovat něco rozsáhlejšího. Lidský mozek se s tím neslučuje. S vývojem počítačů se tak vyvíjely programovací jazyky. Nejprve velmi jednoduché hodně podobné strojovému kódu, akorát místo čísel instrukcí se používaly jejich názvy jako mov, add a podobně. To už bylo pro lidi mnohem lepší, ale zase to bylo nesrozumitelné pro procesor. Proto existoval speciální program, který program napsaný v programovacím jazyku přeložil do strojového kódu. Zjednodušeně řečeno, zaměnil ty názvy za čísla instrukcí a bylo to.

Takto programovat bylo jednodušší, ale člověk pořád musel uvažovat jako stroj, takže bylo stále složité dělat takto větší programy. Člověk si věci zjednodušuje, přemýšlí strukturovaně. A tak vtiskl strukturu i programovacím jazykům. Vznikly v něm přehledné strukturové konstrukce jako procedury, funkce, datové struktury, podmínky, různé druhy cyklů a podobně, které tvořily strukturu programu.

Překladač byl stále složitější program a při převádění těchto struktur na strojový kód se sice pořádně zapotil, ale stálo to za to. Začaly vznikat komplexní programy a počítače se začaly ujímat vlády nad světem. Na stále větší důležitosti a objemu začaly získávat data s kterými se v strukturovaných jazycích pracovalo poněkud těžkopádně. Jazyky se tomu začaly přizpůsobovat, data se začaly členit do objektů a vzniklo objektové programování, propojení dat s kódem.

Tato cesta samozřejmě nebyla jednoduchá a přímočará. Byl to evoluční proces s mnoha slepými větvemi. Lidé zkoušeli kde co, vznikly stovky různých programovacích jazyků, různé způsoby a metody programování. Něco se ujalo, něco ne a tento proces stále pokračuje.

Python je v tomto směru poměrně dosti flexibilní, umožňuje strukturované i objektové programování, dosti toho adoptoval i z funkcionálního programování, umožňuje to všechno elegantně kombinovat a nikomu nic nevnucuje. Je radost v něm programovat.

Kdysi dávno byly počítače drahé, pomalé a měly málo paměti. Šetřilo se každým bitem i instrukcí procesoru. Programovalo se velmi nízkoúrovňově a bylo to složité a zdlouhavé. Jak se postupem času počítače zlevňovaly a současně zrychlovaly, přestávalo to být pravdou. Cena na jednu instrukci rychle klesala a začínalo být ekonomicky výhodnější, když se spíše šetřil čas programátora než procesoru. Programovací jazyky a programy čím dál méně efektivně využívaly procesor a paměť, ale zato byly snadněji použitelné a umožňovaly rychlejší tvorbu komplexnějšího software.

Začalo se rozlišovat, kde se vyplatí šetřit a kde ne. Nízkoúrovňově se programují výkonově kritické funkce. Třeba u přehrávače videa funkce dekódující video data, dekodér. Protože ten provádí miliardy výpočtů po dlouhou dobu a není moc rozsáhlý. Ale zbytek programu, jako uživatelské rozhraní a podobně se programuje vysokoúrovňově. Je to objemově mnohem větší kus kódu než ten dekodér a zároveň oproti němu spotřebuje minimum procesorového času i když funguje třeba jen s desetinovou účinností.

Tento proces umožnil další vývojový stupeň programovacích jazyků. Nejprve se programovalo ve strojovém kódu, potom v kompilovaných jazycích a další evoluční krok jsou interpretované jazyky. Python je interpretovaný jazyk, takže je záhodno si vysvětlit, co to znamená.

Strojový kód je jasný, to jsou číselné instrukce pro procesor, který tento přímo vykonává, to je jednoduché. Kompilovaný programovací jazyk umožnil psaní programů jazykem, který je lidem bližší. Kód napsaný v tomto jazyce se přeloží do strojového kódu a dále už to to samé. Interpretované jazyky na to jdou jinak. Interpretovaný program se nekompiluje do strojového kódu, ale buď do byte kódu a nebo vůbec. Takovým programem se neřídí procesor, ale interpret.

Interpret je program (kompilovaný), který si tak trochu hraje na softwarový procesor. Vykonává instrukce našeho kódu a provádí je, přičemž on sám je samozřejmě prováděn procesorem. Interpretovaný program tak procesor používá nepřímo, prostřednictvím interpretu. Je to pochopitelně pomalejší, ale interpret se za chodu programu dokáže postarat o řadu věcí, čímž vytváření programu  zjednodušuje. Původně se tato interpretace používala u příkazového řádku k jeho skriptování.

V terminálu na příkazovém řádku uživatel píše povely, což jsou jednoduché programy a příkazový řádek je spouští. Třeba kopíruje soubory a podobně. Některé činnosti se opakují, jsou neustále stejné a je nuda psát pořád dokola ty samé povely. Takže se příkazový řádek naučil číst ty povely ze souboru.

No, ne vždy jsou činnosti úplně stejné, někdy je potřeba udělat to a nebo ono, podle toho jestli je tady to tohle nebo onohle. A tak se do těch souborů s povely pro příkazový řádek přidaly jednoduché testy a větvení, což má nějakou syntaxi a tak nám začíná vznikat primitivní programovací jazyk. Postupem času přibudou jednoduché proměnné, pak pole, operace pro vstup a výstup do souboru a ejhle, vždyť ono to je dost podobné programování. Postupem času tyto skriptovací jazyky přešly do podoby plnohodnotných programovacích jazyků a na to skriptování příkazového řádku už se vlastně ani nehodí. Jejich výhodou je to, že jsou uživatelsky velmi přívětivé.

Někteří omezenější programátoři (taky to jsou jen lidi, se všemi slabostmi) odmítají připustit, že by interpretované jazyky byly programovací a programovalo se v nich. Důsledně mluví o skriptování a dívají se na tuto činnost a skriptery s opovržením jako na něco primitivního, nedůstojného.

Pravdou je, že psaní programů v pokročilém interpretovaném jazyce je programování jako každé jiné a pohledem na programový kód ani nelze rozeznat, o jaký jazyk se jedná. Jestli kompilovaný nebo interpretovaný. Resp. jak bude prováděn. Protože třeba existuje interpret pro klasický kompilovaný jazyk C.

Je také pravda, že programování v interpretovaném jazyce bývá jednodušší, ale nelze to vnímat jako primitivní. Jednodušší je to v tom směru, že dosáhnout téhož stojí méně námahy, protože interpret se o některé věci spolehlivě postará, třeba o správu paměti. Na druhou stranu je třeba Python podstatně komplexnější jazyk než jazyk C a dobře ho zvládnout je náročnější.

A zase zpět k počítači

Už je vám myslím dosti jasné, co to je programování, programovací jazyk a jak to tak celé zhruba funguje. Ale protože jsem počítač rozdělil na procesor, paměť a vstupní a výstupní zařízení, řekněme si pro pořádek něco ještě o tech vstupních a výstupních zařízeních. 

Přísně vzato, je i paměť vstupní a výstupní zařízení, ale má výsadní postavení, je pro počítač nezbytná. Vstupní a výstupní zařízení se tak paměti dost podobají. Procesor s nimi komunikuje, vyměňuje si s nimi data. Samozřejmě číselná. 

Třeba takový mikrofon. Když do něj mluvíme, měníme svými hlasivkami tlak vzduchu. Tuto změnu tlaku snímá membrána mikrofonu a převádí jej na elektrický signál, který putuje do AD převodníku, kde se dostatečně rychle snímá aktuální velikost napětí, čímž vzniká dlouhá řada čísel, zdigitalizovaný zvuk. A s touhle řadou čísel si už procesor dobře poradí. Funguj to i naopak, řada čísel může z procesoru proudit na DA převodník, kde z nich vzniká elektrický signál, ten se zesílí v zesilovači a už může putovat do sluchátek nebo reproduktorů, které mají membrány, které rozechvějí vzduch, čímž vzniká zvuk, který vnímáme svým sluchem. Tyto převodníky jsou na zvukové kartě. Teda pokud ještě někdo má zvukovou kartu, dnes už je to spíše přežitek. Obyčejné zvukovky jsou integrované na desce počítače a ty lepší bývají externí a připojují se k počítači přes USB. 

Podobným způsobem se digitalizuje naprosto všechno, co do počítače vstupuje a ještě to není digitální. V počítači je všechno číslo. Díváte se na monitor a prohlížíte krásný obrázek nebo tento text? Někde v útrobách vašeho počítače to je jen dlouhá řada čísel, která se až na obrazovce promění v obraz.

Těch dat je dnes tolik, že je toho na jeden procesor až moc. A tak je těch procesorů v počítači víc. Jeden je hlavní, ten se jmenuje  CPU (centrální procesorová jednotka), ten to všechno řídí a ten i my programujeme. Ale bývají tam běžně i další procesory, třeba v grafické kartě, ve zvukové kartě, v síťové kartě a tak dále. Některé z těchto procesorů jde programovat také, třeba ten v grafické kartě. Jiné nikoliv, na nich běží pevný program, který se snadno změnit nedá. A opět platí, o kartách se mluví z tradice, je to přežitek z dob, kdy počítač byl modulární. Dnes bývá všechno v základu integrované. Grafické procesory dokonce bývají integrované přímo do CPU a jsou jeho součástí. Princip fungování je však stále stejný. Integrace probíhá z důvodu ekonomických.



Žádné komentáře:

Okomentovat