===== 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