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 <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;
}

Součin

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;
}

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

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 <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 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 <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;
}

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 <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;
}

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 <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;
}

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 <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ě.

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 <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
 
zpro/numbers.txt · Last modified: 2020/10/12 17:08 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki