====== 2. Reprezentace dat v paměti a plovoucí řádová čárka ======
* pro vyučující: [[..:..:internal:tutorials:02:start|cvičení 2]]
===== Osnova cvičení =====
- základní reprezentace čísel, uložení v paměti
- plovoucí řádová čárka
- sestavovací program make
- upozornění a příprava na 1. domácí úkol ([[https://dcenet.fel.cvut.cz/apo/]])
**Co si zopakovat na druhé cvičení**
- operace sčítání, odčítání, násobení a dělení
- doplňkový kód
- bitové operace s čísly (and, or, posuny, ...)
- přečíst/zopakovat znalosti z {{ ..:..:lectures:apolos_v11.pdf|APOLOS}}
- reprezentace reálných čísel ([[https://en.wikipedia.org/wiki/IEEE_754|IEEE 754]])
===== Náplň cvičení =====
==== Reprezentace čísel v paměti ====
Na cvičení budeme vycházet z následujícího programu v C, který budeme dále modifikovat.
Program pro zobrazování reprezentace čísel v paměti:
/* Simple program to examine how are different data types encoded in memory */
#include
/*
* The macro determines size of given variable and then
* prints individual bytes of the value representation
*/
#define PRINT_MEM(a) print_mem((unsigned char*)&(a), sizeof(a))
void print_mem(unsigned char *ptr, int size) {
int i;
printf("address = 0x%016lx\n", (long unsigned int)ptr);
for (i = 0; i < size; i++) {
printf("0x%02x ", *(ptr+i)); // == printf("0x%02x ", ptr[i]);
}
printf("\n");
}
int main() {
/* try for more types: long, float, double, pointer */
unsigned int unsig = 5;
int sig = -5;
/* Read GNU C Library manual for conversion syntax for other types */
/* https://www.gnu.org/software/libc/manual/html_node/Formatted-Output.html */
printf("value = %d\n", unsig);
PRINT_MEM(unsig);
printf("\nvalue = %d\n", sig);
PRINT_MEM(sig);
return 0;
}
Zdojový kód programu je z počítačů v laboratoři možné zkopírovat z adresáře ''/opt/apo/binrep/print_binrep''.
K překladu programu použijte buď přímo příkaz:
gcc -Wall -pedantic -o print_binrep ./print_binrep.c
nebo přiložený soubor s popisem sestavení (''Makefile'') pro program 'make'.
K editaci použijte některý z nainstalovaných editorů (geany, vim, emacs, qtcreator, ...).
Pro ty, co nemají vlastní preferenci je vhodné začít třeba s programem [[https://www.geany.org/|geany]].
==== Sestavovací program make ====
V situaci, kdy máme jeden zdrojový soubor není problém spouštět překladač pokaždé ručně. U větších projektů ale máme souborů víc a často různých typů – máme třeba zdrojové kódy v C a v assembleru, dokumentaci v XML a třeba i něco dalšího. Překládat ručně každý soubor zvlášť a ještě k tomu jiným překladačem a spojovat výsledek dohromady je zbytečně velká práce. Proto byl vymyšlen program [[https://www.gnu.org/software/make/manual/html_node/index.html|make]]. Jeho základní myšlenka je ta, že se popíše jak se překládá který typ souboru a stanoví se které soubory jsou potřeba pro "vyrobení" jiného souboru.
Program make funguje tak, že po spuštění si přečte soubor Makefile, kde jsou zapsána pravidla pro kompilaci a vyvolává postupně překladače tak, jak je potřeba.
V souboru ''Makefile'' existují čtyři typy řádek:
* popis závislostí,
* příkazy pro kompilaci,
* nastavování proměnných,
* komentáře.
Nejjednodušší Makefile pro kompilaci programu hello vypadá následovně.
hello: hello.c
Obsahuje pouze jednu řádku s popisem závislostí. Takto zapsaná řádka říká, že pro vytvoření souboru hello je potřeba soubor ''hello.c''. Tomu, co je vlevo od dvojtečky se říká target (cíl) a vše co je napravo jsou takzvané prerekvizity.
Program make má v sobě vestavěna implicitní pravidla, díky nimž ví, jak má provést překlad. Kdyby tato pravidla neexistovala, musel by náš ''Makefile'' vypadat takto:
hello: hello.c
gcc -Wall -o hello hello.c
Na druhé řádce, která začíná tabulátorem, je příkaz, který bude vykonán pokud make usoudí, že je potřeba překompilovat soubor ''hello''.
Implicitní pravidla říkají, jak z jednoho typu souboru vyrobit jiný typ souboru. Tato pravidla jsou většinou definována pomocí proměnných. Chceme-li implicitní pravidlo jen trochu pozměnit, nemusíme ho definovat znova, ale stačí změnit jen hodnoty proměnných, které se v pravidlech používají.
CFLAGS = -g -Wall
CC = m68k-elf-gcc
hello: hello.c
Pomocí proměnné ''CFLAGS'' se například určuje, s jakými přepínači má být spouštěn překladač jazyka C. Jak se jmenuje překladač se zase specifikuje v proměnné ''CC''[3].
Pokud chceme překládat větší projekt, bývá zvykem rozšířit ''Makefile'' o další targety:
all: hello
clean:
rm -f hello
hello: hello.c
gcc -Wall -g -o hello hello.c
O programu make by toho šlo napsat mnohem víc. Jdou pomocí něj překládat i velmi komplikované projekty jako například samotné jádro Linuxu. Vetšinou není potřeba vytvářet složité soubory Makefile ručně. Nástroje jako Meson, CMake, autoconf či nějaké IDE Makefile generují automaticky.
==== Úkoly ====
//Pokračování prvního cvičení.//
- **Vyzkoušejte si ručně sčítání a odčítání celých čísel v doplňkovém kódu**
* demonstrujte výpočet např. ''7+6, 7-6''
* procvičte výpočet na dalších číslech a s pomocí programu výsledky ověřte
* kdy může dojít k přetečení a jak poznáte, že k němu došlo?
- **Násobení celých čísel**
* demonstrujte výpočet např. ''7*6''
* jak se výpočet změní v případě záporných čísel? např. ''-7*6, -7*(-6), 7*(-6)''
* rychlá verze hw násobičky (jak zrychlit opakované sčítání na jedné sčítačce použitím většího množství sčítaček?)
- **Dělení celých čísel**
* demonstrujte výpočet např. ''42/7, 43/7''
* jak se výpočet změní v případě záporných čísel?
//Nové úkoly tohoto cvičení.//
- **Přeložte a spusťte uvedený program, interpretujte výstupy programu a postupně ho modifikujte tak**
* aby tiskl vnitřní reprezentaci i jiných datových typů (např. ''char, float, long, int*'')
* aby vytiskl tabulku celých čísel včetně jejich reprezentace v rozsahu ''-16'' až ''15''
* aby realizoval operace sčítání a odčítání dvou proměnných (celá čísla) a vytiskl na obrazovku vstupní operandy a výsledky těchto operací včetně jejich vnitřní reprezentace
* vyzkoušejte operace s kladnými i zápornými čísly, zaměřte se i na takové hodnoty, kdy po provedení operace dojde k přetečení
- **Reprezentace reálných čísel (IEEE 754)**
* binární reprezentace reálných čísel (''float - 32bit, double - 64bit'')
* převeďte na binární reprezentaci číslo ''-0.75'', ověřte správnost s pomocí programu pro zobrazení reprezentace v paměti
* převeďte float z binární reprezentace ''0xC0A00000'' na reálné číslo v desitkové soustavě
* demonstrujte výpočet (v desítkové soustavě) ''9.999*10^1 + 1.1610*10^(-1)'', předpokládejte, že je možné uložit pouze 4 cifry čísla a 2 cifry exponentu.
* Návod:
- zarovnání čísel
- součet
- normalizace
- zaokrouhlení
* v binární reprezentaci sečtěte čísla ''0.5'' a ''-0.4375''
* demonstrujte výpočet (v desítkové soustavě) ''1.110*10^10 * 9.200*10^(-5)''
* v binární reprezentaci vynásobte čísla ''0.5'' a ''-0.4375''
===== Domácí úkoly =====
* domácí úkoly 1 až 4 budou zadané a odevzdávané elektronickou formou
* vstup k zadání a odevzdání úkolů je přes adresu [[https://dcenet.fel.cvut.cz/apo/|https://dcenet.fel.cvut.cz/apo/]]
* Na stránce "Assignments" naleznete seznam zadaných úkolů
* Pro nácvik práce s odevzdávacím systémem je k dispozici nehodnocená varianta prvního úkolu **1st training homework**, kde máte 999 pokusů. Nazapočítávají se z ní body, ale i tak ji musíte vyřešit aspoň na polovinu, tedy na 3 body, abyste směli odevzdat 1. hodnocený domácí úkol.
* Případnými problémy s odevzdávacím systémem se obracejte na svého cvičícího nebo přímo na autora/správce systému [[courses:b35apo:teacher:susta:start|Richarda Šustu]]
----
===== Užitečné odkazy =====
* [[http://support.dce.felk.cvut.cz/pos/cv-langc/|http://support.dce.felk.cvut.cz/pos/cv-langc/]] - Základy jazyka C
* [[http://www.gnu.org/software/libc/manual/html_node/Formatted-Output.html|http://www.gnu.org/software/libc/manual/html_node/Formatted-Output.html]] - Dokumentace k řízení formátovaného výstupu pro implementaci **printf** z knihovny funkcí pro jazyk C ([[http://www.gnu.org/software/libc/|GLIBC]]) z projektu [[http://www.gnu.org/|GNU]]
* [[https://bootlin.com/doc/legacy/command-line/command_memento.pdf|Základní příkazy pro práci v příkazové řádce]] na [[https://bootlin.com/|Bootlin]]
* Materiál k IEEE 754: {{..:apo2.pdf|}}, nová česká verze APO2020_cv2 {{ :courses:b35apo:tutorials:02:apo2020_cv2.pdf | PDF }} a {{ :courses:b35apo:tutorials:02:apo2020_cv2.pptx | PPTX}}
* Popis formátu IEEE 754 na [[https://en.wikipedia.org/wiki/IEEE_754|Wikipedii]]
* [[https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/fp-bit.c]] - implementace operací v plovoucí řádové čárce s využitím operací v pevné řádové čárce tak v knihovně kompilátoru [[http://gcc.gnu.org|GCC]] pro procesory, které hardwarovou implementací operací nedisponují.