Lekce 14 - Matematické funkce v C++
V minulé lekci, Vícerozměrná pole v jazyce C++, jsme se naučili používat vícerozměrná pole.
V dnešním tutoriálu kurzu základů jazyka C++ se podíváme na
standardní knihovnu cmath
. Ta poskytuje velké množství funkcí
pro řešení obvyklých matematických problémů, ty nejdůležitější z
nich si uvedeme.
fmin()
, fmax()
,
fdim()
Začněme s tím jednodušším Všechny funkce přijímají jako parametr dvě čísla typu
double
. Funkce fmin()
vrátí to menší, funkce
fmax()
to větší z nich. Funkce fdim()
vrátí
x-y
, je-li x > y
. V ostatních případech vrací
0
.
round()
, ceil()
,
floor()
a trunc()
Všechny funkce se týkají zaokrouhlování a přijímají parametry typu
double
. Návratová hodnota je pro všechny funkce rovněž typu
double
. Funkce round()
vrací zaokrouhlené číslo
tak, jak to známe ze školy (od 0.5
nahoru, jinak dolů). Funkce
ceil()
zaokrouhlí vždy nahoru a floor()
vždy dolů.
A funkce trunc()
nezaokrouhluje, pouze odtrhne desetinnou
část.
Funkci round()
budeme jistě potřebovat často, další funkce
jsem často použil například když jsem zjišťoval počet položek na
stránce (např. nějaké tabulky v konzoli). Máme-li 33
položek
a na stránce jich je vypsáno 10
, budou matematicky zabírat
3.3
stránek. Výsledek musíme zaokrouhlit nahoru, protože v
reálu stránky budou samozřejmě 4
.
Pokud vás napadlo, že floor()
a trunc()
dělají
to samé, chovají se jinak u záporných čísel. Tehdy floor()
zaokrouhlí na číslo více do mínusu, trunc()
zaokrouhlí vždy
k nule.
Zaokrouhlení desetinného čísla a jeho uložení do proměnné typu
int
tedy provedeme následujícím způsobem:
double d = 2.72; int a = (int)round(d);
Přetypování na int
je nutné, jelikož round()
vrací sice celé číslo, ale stále uložené v typu double
a to
kvůli tomu, aby všechny matematické funkce měly stejné rozhraní. Proto si
již nebudeme u zbylých funkcí typy uvádět - vždy to bude
double
.
abs()
a signbit()
Funkce abs()
vrátí absolutní hodnotu parametru a
signbit()
vrátí 1
, je-li číslo záporné, ve
zbylých případech vrací 0
. Funkce signbit()
není
podporovaná ve všech kompilerech, proto je možné, že ji nemusíte mít
dostupnou.
sin()
, cos()
,
tan()
Klasické goniometrické funkce přijímají jako parametr úhel v
radiánech, nikoli ve stupních. Pro konverzi stupňů na
radiány stupně vynásobíme hodnotou (M_PI / 180)
.
acos()
, asin()
,
atan()
Opět klasické cyklometrické funkce (arkus funkce), které podle hodnoty
goniometrické funkce vrátí daný úhel. Jedná se o inverzní funkce k
sin()
, cos()
a tan()
. Parametrem je
hodnota úhlu, výstupem úhel v radiánech. Pokud si přejeme mít úhel ve
stupních, vynásobíme radiány hodnotou (180 / M_PI)
.
pow()
a sqrt()
Funkce pow()
přijímá dva parametry, první je základ mocniny
a druhý exponent. Pokud bychom tedy chtěli vypočítat např. 23,
kód by byl následující:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double vysledek = pow(2, 3);
cout << vysledek;
return 0;
}
Sqrt
je zkratka ze square root a vrací druhou odmocninu z
daného čísla.
exp()
, log()
,
log10()
Funkce exp()
vrací Eulerovo číslo, umocněné na daný
exponent. Funkce log()
vrací přirozený logaritmus daného
čísla. A funkce log10()
vrací dekadický logaritmus daného
čísla.
V seznamu metod nápadně chybí libovolná odmocnina. My ji však dokážeme spočítat i na základě funkcí, které knihovna poskytuje.
Víme, že platí: 3. odm. z 8 = 8^(1/3)
. Můžeme tedy
napsat:
{CPP_IMPORTS}
#include <cmath>
{CPP_MAIN_BLOCK}
double vysledek = pow(8, (1.0/3.0));
cout << vysledek;
{/CPP_MAIN_BLOCK}
Je velmi důležité, abychom při dělení napsali alespoň jedno číslo s
desetinnou tečkou, jinak bude C++ předpokládat celočíselné dělení a
výsledkem by v tomto případě bylo 8^0 = 1
.
Dělení
Programovací jazyky se často odlišují tím, jak v nich funguje dělení čísel. Tuto problematiku je nutné dobře znát, abyste nebyli překvapeni. Napišme si jednoduchý program:
{CPP_CONSOLE}
int a = 5 / 2;
double b = 5 / 2;
double c = 5.0 / 2;
double d = 5 / 2.0;
double e = 5.0 / 2.0;
int f = 5 / 2.0;
cout << "a=" << a << " b=" << b << " c=" << c << " d=" << d << " e=" << e << " f=" << f << endl;
{/CPP_CONSOLE}
V kódu několikrát dělíme 5 / 2
, což je matematicky
2.5
. Jistě ale tušíte, že výsledek nebude ve všech
případech stejný. Troufnete si tipnout, co kdy vyjde? Zkuste to
Konzolová aplikace
a=2 b=2 c=2.5 d=2.5 e=2.5 f=2
Vidíme, že výsledek dělení je někdy celočíselný a někdy reálný. Přitom nezáleží pouze na datovém typu proměnné, do které výsledek ukládáme, ale na datovém typu čísel, které dělíme. Pokud je jedno z čísel desetinné, je výsledek vždy desetinné číslo. Dvě celá čísla vždy vrátí celé číslo, dejte si na to pozor např. když budete počítat průměr. Pro desetinný výsledek je nutné alespoň jednu proměnnou přetypovat na desetinné číslo.
int soucet = 10; int pocet = 4; double prumer = (double)soucet / (double)pocet;
Pozn.: Např. v jazyce PHP je výsledek dělení vždy desetinný. Až budete dělit v jiném programovacím jazyce než je C++, zjistěte si, jak dělení funguje, než jej použijete.
Zbytek po celočíselném dělení
V našich aplikacích můžeme často potřebovat zbytek po celočíselném
dělení (tzv. modulo). U našeho příkladu 5 / 2
je
celočíselný výsledek 2
a modulo 1
(zbytek). Modulo
se často používá pro zjištění, zda je číslo sudé (zbytek po dělení
2
je 0
) nebo když chcete zjistit odchylku vaší
pozice od nějaké čtvercové sítě.
V C++ a obecně v céčkových jazycích (tzv. C-like jazyky) zapíšeme
modulo jako %
:
{CPP_CONSOLE}
cout << "Zbytek po deleni 5/2 je " << 5 % 2 << endl;
{/CPP_CONSOLE}
Tak to bychom měli.
V následujícím cvičení, Řešené úlohy k 12.-14. lekci C++, si procvičíme nabyté zkušenosti z předchozích lekcí.