Lekce 12 - Matematické funkce v jazyce C
V minulé lekci, Vícerozměrná pole v jazyce C, jsme si představili vícerozměrná pole.
V dnešním tutoriálu kurzu základů jazyka C se podíváme na standardní
knihovnu math.h
. 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
. round()
vrací zaokrouhlené
číslo tak, jak to známe ze školy (od 0.5
nahoru, jinak dolů).
ceil()
zaokrouhlí vždy nahoru a floor()
vždy dolů.
trunc()
nezaokrouhluje, pouze odtrhne desetinnou část.
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
nebudu u zbylých funkcí typy uvádět - vždy bude double
.
abs()
a signbit()
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()
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 <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char** argv)
{
double vysledek = pow(2,3);
printf("%lf", vysledek);
return (EXIT_SUCCESS);
}
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. 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:
{C_IMPORTS}
#include <math.h>
{C_MAIN_BLOCK}
double vysledek = pow(8, (1.0/3.0));
printf("%lf", vysledek);
{/C_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:
{C_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;
printf("a=%d b=%f c=%f d=%f e=%f f=%d", a, b, c, d, e, f);
{/C_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.000000 c=2.500000 d=2.500000 e=2.500000 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. 2 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éčku a obecně v céčkových jazycích (tzv. C-like jazyky) zapíšeme
modulo jako %
:
{C_CONSOLE}
printf("Zbytek po deleni 5/2 je %d", 5 % 2);
{/C_CONSOLE}
Tak to bychom měli.
V následujícím cvičení, Řešené úlohy k 11. a 12. lekci Céčka, si procvičíme nabyté zkušenosti z předchozích lekcí.