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
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.
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; }
Sečteme druhé mocniny od jedné do deseti
#include <iostream> 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 <iostream> 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; }
Zkusíme vypočítat faktoriál
#include <iostream> 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 <iostream> 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; }
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 <iostream> 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í
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 <iostream> 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 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 <iostream> 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 <iostream> 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; }
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 <iostream> 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; }
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'; } }
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 <iostream> 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; }
Výsledkem porovnání je logická hodnota true nebo false typu bool.
*&&* 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 + , - , * , / , % (zbytek po dělení, jen po celá čísla)
pokud jsou oba operandy celočíselné je výsledek celočíselný
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 <iostream> 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ě.
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 <iostream> 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