===== Podmíněný příkaz ===== Připomenu příkazy z přednášky if ( podmínka ) { příkazy prováděné pokud je podmínka splněna } if ( podmínka ) { příkazy prováděné pokud je podmínka splněna } else { příkazy prováděné pokud není podmínka splněna } Podmínka musí být v kulatých závorkách ===== Příkaz cyklu ===== while ( podmínka ) { příkazy opakovaně prováděné dokud je podmínka platí } Pokud na začátku cyklu není podmínka splněna, cyklus nepoběží ani jednou. ===== Příkaz for ===== for ( inicializace ; podmínka ; závěrečná instrukce ) { opakovaně prováděné příkazy } je totéž jako inicializace while (podmínka ; závěrečná instrukce ) { příkazy opakovaně prováděné závěrečná instrukce } Pokud na začátku cyklu není podmínka splněna, cyklus nepoběží ani jednou. V inicializaci můžeme deklaravat novou proměnnou, která existuje jen po dobu běhu cyklu, např. for (int i = 1 ; i <= 10 ; i++) { cout << i << endl; } ===== Součet druhých mocnin ===== Sečteme druhé mocniny od jedné do deseti #include using namespace std; int main () { int sum = 0; for (int i = 1; i <= 10; i++) { cout << i << endl; sum = sum + i * i; } cout << "soucet druhych mocnin je " << sum << endl; } Pokud sčítáme desetinná čísla, deklarujeme **sum** typu **double**. #include using namespace std; int main () { double sum = 0; for (int i = 1; i <= 10; i++) { sum = sum + 1 / (i * i); } cout << "soucet je " << sum << endl; } ===== Součin ===== Zkusíme vypočítat faktoriál #include using namespace std; int main () { int n = 10; long long result = 1; for (int i = 1; i <= n; i++) { result = result * i; } cout << "faktorial " << n << " je " << result << endl; } 64 bitový celočíselný typ **long long** nám vystačí do 20! Trochu předbíhám, ale faktoriál by se mohl hodit jako funkce. Nejprve si ukážeme definici funkce **f**, která má dva parametry **x** a **y** typu **double** a výsledek funkce je také typu **double**. double f (double x, double y) { return sqrt (x * x + y * y); } Nyní zkusíme napsat funkci **fact** s celočíselným parametrem, jejíž výsledky jsou typu **double**. #include using namespace std; double fact (int n) { double result = 1; for (int i = 1; i <= n; i++) { result = result * i; } return result; } int main() { int n = 10; cout << "faktorial " << n << " je " << fact (n) << endl; int k = 2; double c = fact(n) / (fact(n - k) * fact(k)); cout << "kombinacni cislo " << n << " nad " << k << " je " << c << endl; } ===== Převod čísla do dvojkové soustavy ===== Nejprve od nejnižších řádů k vyšším Zbytek po dělení dvěmi určí nejnižší dvojkovou cifru. Celočíselné dělení dvěmi odstraní nejnižší cifru #include using namespace std; int main () { int n = 12; const int zaklad = 2; while (n > 0) { cout << n % zaklad << endl; // jedna cislice n = n / zaklad; // odstranime nejnizsi cislici } } Výstup pro 12 0 0 1 1 Můžete si totéž představit pro desítkouvou soustavu (zaklad=10), program bude vypisovat desítkové cifry, opět v opačném pořadí ==== Proměnná typu string pro uložení číslic ===== Připravím si proměnnou typu řetěrec (posloupnost) znak inicializovanou na prázdný řetězec. string s = ""; Pokud je číslo sudé, přidám do proměnné **s** číslici nula. Číslice bude znakového typu (**char**). \\ Sčítání dvou řetězcových proměnných je definováno jako skládání dvou posloupností znaků za sebe. \\ Sčítání řetězcové proměnné a znaku je také definováno jako skládání. s = '0' + s; Novou číslici přidáváme před dříve vypočtené číslice nižžšího řádu. \\ Nakonec řetězec vytiskneme. \\ (Pokud také chceme vytisknout původní **n**, musíme si uvědomi, že jsme v průbehu programu proměnnou **n** vynulovali.) #include using namespace std; int main() { int n = 12; string s = ""; while (n > 0) { if (n % 2 == 0) // zbytek po deleni 2 predstavuje nejnizsi cislici { s = '0' + s; } else { s = '1' + s; } n = n / 2; // odstranime nejnizsi cislici } cout << s << endl; } ==== Funkce pro převod do dvojkové soustavy ==== Funkce **conv** mít výsledek typu **string**. \\ První parametr bude převáděné celé číslo. \\ Nepovinným druhým parametrem bude základ číselné soustavy, pokud parametr nezadáme, použije se hodnota 2. V proměnné **k** budeme mít jednu číslici jako číslo od **0** do **zaklad-1**. \\ Proměnná **digit** bude obsahovat číslici jako ascii znak. Nula má v ascii abecedě vnitřní kód 48. \\ Jednička 49, atd. \\ Znaková konstanta nula v jednoduchých uvozovkách **'0'** představuje 48. \\ Sčítání **char** a **int** je definováno jako znak s pozměněným vniřním kódem. '0' + 0 je '0' \\ '0' + 1 je '1' \\ '0' + 9 je '9' 'a' + 1 je 'b' \\ 'A' + 2 je 'C' #include using namespace std; string conv (int n, int zaklad = 2) { string s = ""; while (n > 0) { int k = n % zaklad; // ziskame nejnizsi cislici jako cislo od 0 do zaklad-1 char digit = '0' + k; // prevedeme cislo na znak s = digit + s; n = n / zaklad; // odstranime nejnizsi cislici } return s; } int main() { int n = 12; cout << n << " ve dvojkove soustave je " << conv(n) << endl; cout << "v osmickove soustave " << conv(n, 8) << endl; cout << "v desitkove soustave " << conv(n, 10) << endl; } 12 ve dvojkove soustave je 1100 v osmickove soustave 14 v desitkove soustave 12 Pokud chceme soustavy se základem většíim než 10 ( a menším než 37 ), \\ musíme číslici s hodnotou 10 převédst na písmeno A, \\ ale písmena nenásledují v ascii abecedě bezprostředně za číslicemi char digit; if (k <= 9) { digit = '0' + k; // prevedeme cislo na znak } else { digit = 'A' + k - 10; // 10 prevedeme na A, 11 na B, ... } Celý program #include using namespace std; string conv (int n, int zaklad = 2) { string s = ""; while (n > 0) { int k = n % zaklad; // ziskame nejnizsi cislici jako cislo od 0 do zaklad-1 char digit; if (k <= 9) { digit = '0' + k; // prevedeme cislo na znak } else { digit = 'A' + k - 10; // 10 prevedeme na A, 11 na B, ... } s = digit + s; n = n / zaklad; // odstranime nejnizsi cislici } return s; } int main() { int n = 12; cout << n << " ve dvojkove soustave je " << conv(n) << endl; cout << "v osmickove soustave " << conv(n, 8) << endl; cout << "v desitkove soustave " << conv(n, 10) << endl; cout << "v sestnastkove soustave " << conv(n, 16) << endl; } ==== Nula a záporné hodnoty ==== Pro nulu by naše funkce vyprodukovala prázdný řetězec. Promměnná **zaporne** typu **bool** bude obsahovat **true**, pokud je původní **n** záporné. #include using namespace std; string conv (int n, int zaklad = 2) { string s = ""; if (n == 0) { s = "0"; } else { bool zaporne = (n < 0); if (zaporne) { n = -n; } while (n > 0) { int k = n % zaklad; // ziskame nejnizsi cislici jako cislo od 0 do zaklad-1 char digit; if (k <= 9) { digit = '0' + k; // prevedeme cislo na znak } else { digit = 'A' + k - 10; // 10 prevedeme na A, 11 na B, ... } s = digit + s; n = n / zaklad; // odstranime nejnizsi cislici } if (zaporne) { s = '-' + s; } } return s; } int main() { cout << conv(0) << endl; cout << conv(-12) << endl; } ==== Poznámka pod čarou - rekurze ===== Původní postup s cyklem, který číslice vypisuje v opačném pořadí void conv1 (int n) { while (n > 0) { if (n % 2 == 0) { cout << '0'; } else { cout << '1'; } n /= 2; } } Rekurzivní varianta, která stále vypisuje číslice v opačném pořadí void conv2 (int n) { if (n % 2 == 0) // zbytek po deleni 2 predstavuje nejnizsi cislici { cout << '0'; } else { cout << '1'; } if (n/2 > 0) { conv2 (n / 2); } } Rekurzivní varianta, která vypisuje číslice v obvylkém pořadí void conv3 (int n) { if (n / 2 > 0) { conv3 (n / 2); } if (n % 2 == 0) { cout << '0'; } else { cout << '1'; } } ===== Převod řetězce znaků na číslo ===== Pokud jste vydrželi až sem, tak Vám děkuji. A pokud Vás zajímá převod z řetězce znaků na číslo, tak je zde. Někdy se na něj podíváme podrobněji. #include using namespace std; int convFromString (string s, int zaklad = 2) { int vysledek = 0; bool zaporne = false; int delka = s.length(); // delka retezce for (int i = 0; i < delka; i++) // jednotlive znaky se indexuji od nuly do delka-1 { char c = s[i]; // i-ty znak ze vstupniho retezce // cout << "cislice " << c << endl; if (c == '-') { zaporne = true; // v nasem programu minus nemusi byt na zacatku } else if (c == ' ') // porovnavani pomoci == , nikoliv = { // mezery preskocime } else if (c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { int digit; if (c >= '0' && c <= '9') { digit = c - '0'; // cislo od 0 do 9 } else if (c >= 'A' && c <= 'Z') { digit = c - 'A' + 10; // A bude 10, atd. } else if (c >= 'a' && c <= 'z') { digit = c - 'a' + 10; // a bude 10, atd. } // cout << "cislice " << c << " ma hodnotu " << digit << endl; if (digit >= zaklad) { cerr << "Podivna cislice " + digit << endl; } else { vysledek = vysledek * zaklad + digit; } } else { cerr << "Podivny znak " + c << endl; } } if (zaporne) { vysledek = - vysledek; } return vysledek; } int main() { cout << convFromString ("- 1110") << endl; cout << convFromString ("fe", 16) << endl; } Zjednodušená varianta jen pro desítkové číslice int convFromString (string s, int zaklad = 2) { int vysledek = 0; int delka = s.length(); // delka retezce for (int i = 0; i < delka; i++) // jednotlive znaky se indexuji od nuly do delka-1 { char c = s[i]; // i-ty znak ze vstupniho retezce int digit = c - '0'; // cislo od 0 do 9 vysledek = vysledek * zaklad + digit; } return vysledek; } Varianta předpokládající na vstupu jen číslice a písmena int convFromString (string s, int zaklad = 2) { int vysledek = 0; int delka = s.length(); // delka retezce for (int i = 0; i < delka; i++) // jednotlive znaky se indexuji od nuly do delka-1 { char c = s[i]; // i-ty znak ze vstupniho retezce int digit; if (c >= '0' && c <= '9') digit = c - '0'; // cislo od 0 do 9 else if (c >= 'A' && c <= 'Z') digit = c - 'A' + 10; else if (c >= 'a' && c <= 'z') digit = c - 'a' + 10; vysledek = vysledek * zaklad + digit; } return vysledek; } ===== Poznámky o používaných typech ===== * **int** - celá čísla (podmnožina celých čísel, v dnešních překladačích od -231 do 231-1, tj. asi od -2.109 do 109) * **double** - reálná čísla (přesněji podmnožina racionálních čísel, v současných překladačích uložené jako 8 bytů) * **float** - reálná čísla s menší přesností (v současnosti 4 byty) * **bool** - logické hodnoty **true** a **false** * **char** - ascii znaky zapisované v __jednoduchých uvozovkách__, např. **'a'**, **'Z'**, **'1'** nebo mezera **' '**. * **string** (std::string) - posloupnosti znaků zapisované v __dvojitých uvozovkách__, např. prázdný řetězec **""**, řetězec obsahující jeden znak **"a"**, tříznakový řetězec **"abc"** * **long long** (nebo **long long int**, případně **int64_t**) - v některých překladačích celá čísla uložené jako 8 bytů, od -263 do 263-1, to je přibližně od -8.1018 do 8.1018) === příklady zápisu čísel === * **double** : 1.0 , 3.14 , 5.5e9 (5,5.109) * **float** na konci přidáváme **f** : 1.0f , 3.14f , 5.5e9f * upozornění: celá čísla začínající nulou jsou v __osmičkové soustavě__: 017 ( 15 v desítkové soustavě ) * celá čísla začínající **0x** jsou v šestnáctové soustavě: 0xff ( 255 v desítkové soustavě ) * **long long** na konci přidáváme **ll**, u novějších překladačů číslice můžeme odlělovat jednoduchou uvozovkou : 100ll , 1'000'000'000'000ll === releace pro porovnávání === * porovnávání na rovnost zapisujeme pomocí dvou rovnítek **==** ( jedno rovnítko je přiřazovací příkaz ) * nerovná se zapisejeme pomocí vykřičníku a rovnítka **!=** * menší, větší obvyklým způsobem **<** , **>** * menší nebo rovno, větší nebo rovno **< =** , **>=** Výsledkem porovnání je logická hodnota **true** nebo **false** typu **bool**. === and , or === * logický součin (konjunkci, and) dvou logických hodnot zapisujeme **&&** * logický součet (disnjunkci, or) zapisujeme **||** *&&* má lepší prioritu než **||** Později si vysvětlíme **&** a **|** a ještě si upřesníme způsob vyčíslování operandů **&&** a **||** === aritmetické operace === aritmetické operace ** + **, ** - **, ** * **, ** / **, ** % ** (zbytek po dělení, jen po celá čísla) pokud jsou oba operandy celočíselné je výsledek celočíselný ===== Poznámka pod čarou - výsledný typ aritmetické operace ===== pokud je alespoň jeden operand **double** je výsledek **double** pokud je alespoň jeden operand **float** a žádný operand není **double** je výsledek **float** pokud je alespoň jeden operand **long long** a žádný operand není **float float** ani **double** je výsledek **long long** Kdo si to má pamatovat ? Můžete zkusit příklad: #include using namespace std; void check (int n) { cout << "Parametr typu int: " << n << endl; } void check (long long n) { cout << "Parametr typu long long: " << n << endl; } void check (float f) { cout << "Parametr typu float: " << f << endl; } void check (double x) { cout << "Parametr typu double: " << x << endl; } int main() { check (1 + 1); check (1 + 1.0); check (1.0f + 1.0f); // check (2'000'000'000 + 2'000'000'000); // check (2'000'000'000ll + 2'000'000'000); // check (8'000'000'000 + 2e10f); // check (8'000'000'000 + 2e10); } Výstup je Parametr typu int: 2 Parametr typu double: 2 Parametr typu float: 2 Hodně předbíhám: C++ dovoluje __přetěžované__ (overloaded) funkce, které jsou deklararovány několikrát se stejným jménem, ale rozdílnými parametry. \\ Překladač při volání funkce vybere funkci podle typu/typů zadaných parametrů. To využívá náš příklad. \\ Předefinovaná operace **<<**, kterou používaná při výstupu do **cout**, je také deklarována pro různé typy parametrů na pravé straně. ===== Poznámka - největší hodnoty celočíselných typů ==== Hledáme největší hodnoty, které lze uložit do různých celočíselných typů. \\ (Výsledky se mohou pro různé překladače lišit.) #include using namespace std; int main () { // vybereme si jeden typ // typedef short T; // typedef unsigned short T; // typedef int T; // typedef unsigned int T; // typedef long T; // typedef unsigned long T; typedef long long T; // typedef unsigned long long T; T n = 1; T top = n; cout << top << endl; // at vypis zacina jednickou T next = 2 * n + 1; while (next > n) { top = next; // zapamatovat cout << top << endl; n = n * 2 + 1; // dalsi n next = n * 2 + 1; // n posunute o dvojkovou cifru vlevo a na konec pridame jednicku } cout << endl; cout << "top " << top << endl; next = top + 1; cout << "top+1 " << next << endl; } 1 3 7 15 31 63 127 255 511 1023 ... 1152921504606846975 2305843009213693951 4611686018427387903 9223372036854775807 top 9223372036854775807 top+1 -9223372036854775808