12. díl - Matematické funkce v C# a knihovna Math

C# .NET Základní konstrukce Matematické funkce v C# a knihovna Math American English version English version

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Vícerozměrná pole v C# .NET, jsme si představili vícerozměrná pole. Naše výuka C# .NET teď vlastně teprve začíná, nicméně tento on-line kurz těch nejzákladnějších konstrukcích jazyka již dokončujeme. Jsem rád, že jsme se úspěšně dostali až sem, další on-line kurz se totiž bude věnovat objektově orientovanému programování. Budeme tam vytvářet opravdu zajímavé aplikace a i jednu hru. Sekci zakončeme odlehčujícím článkem s přehledem matematických funkcí, které se nám v našich programech jistě budou v budoucnu hodit.

Základní matematické funkce jsou v .NET obsaženy v třídě Math. Třída nám poskytuje dvě základní konstanty: PI a E. PI je pochopitělně číslo Pí (3.1415...) a E je Eulerovo číslo, tedy základ přirozeného logaritmu (2.7182...). Asi je jasné, jak se s třídou pracuje, ale pro jistotu si na ukázku konstanty vypišme do konzole:

Console.WriteLine("Pí: {0} \ne: {1}", Math.PI, Math.E);
Console.ReadKey();

Vidíme, že vše voláme na třídě Math. Na kódu není nic moc zajímavého kromě toho, že jsme v textovém řetězci použili speciální znak \n, který způsobí odřádkování.

Konzolová aplikace
Pí: 3.14159265358979
e: 2.71828182845905

Pojďme si nyní popsat metody, které třída poskytuje:

Metody na třídě Math

Min(), Max()

Začněme s tím jednodušším :) Obě funkce berou jako parametr dvě čísla libovolného datového typu. Funkce Min() vrátí to menší, funkce Max() to větší z nich.

Round(), Ceiling(), Floor() a Truncate()

Všechny tři funkce se týkají zaokrouhlování. Round() bere jako parametr desetinné číslo a vrací zaokrouhlené číslo typu double tak, jak to známe ze školy (od 0.5 nahoru, jinak dolů). Ceiling() zaokrouhlí vždy nahoru a floor() vždy dolů. Truncate() nezaokrouhluje, pouze odtrhne desetinnou část.

Round() budeme jistě potřebovat často, další funkce jsem prakticky často použil např. při zjišťování počtu stránek při výpisu komentářů v knize návštěv. Když máme 33 příspěvků a na stránce jich je vypsáno 10, budou tedy 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 Truncate() dělají to samé, chovají se jinak u záporných čísel. Tehdy Floor() zaokrouhlí na číslo více do mínusu, Truncate() 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)Math.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 pracovaly s typem double.

Abs() a Sign()

Obě metody berou jako parametr číslo libovolného typu. Abs() vrátí jeho absolutní hodnotu a Sign() vrátí podle znaménka -1, 0 nebo 1 (pro záporné číslo, nulu a kladné číslo).

Sin(), Cos(), Tan()

Klasické goniometrické funkce, jako parametr berou úhel typu double, který považují v radiánech, nikoli ve stupních. Pro konverzi stupňů na radiány stupně vynásobíme * (Math.PI/180). Výstupem je opět double.

Acos(), Asin(), Atan()

Opět klasické cyklometrické funkce (arkus funkce), které podle hodnoty goniometrické funkce vrátí daný úhel. Parametrem je hodnota v double, výstupem úhel v radiánech (také double). Pokud si přejeme mít úhel ve stupních, vydělíme radiány / (180 / Math.PI).

Pow() a Sqrt()

Pow() bere dva parametry typu double, první je základ mocniny a druhý exponent. Pokud bychom tedy chtěli spočíst např. 23, kód by byl následující:

Console.WriteLine(Math.Pow(2, 3));

Sqrt() je zkratka ze square root a vrátí tedy druhou odmocninu z daného čísla typu double. Obě funkce vrací výsledek jako double.

Exp(), Log(), Log10()

Exp() vrací Eulerovo číslo, umocněné na daný exponent. Log() vrací přirozený logaritmus daného čísla. Log10() vrací potom 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é Math poskytuje.

Víme, že platí: 3. odm. z 8 = 8^(1/3). Můžeme tedy napsat:

Console.WriteLine(Math.Pow(8, (1.0/3.0)));

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 80 = 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 poté (nepříjemně) překvapeni. Napišme si jednoduchý program:

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;

Console.WriteLine("{0}\n{1}\n{2}\n{3}\n{4}", a, b, c, d, e);
Console.ReadKey();

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 si co kdy vyjde? Zkuste to :)

Kód by se nepřeložil kvůli řádku s proměnnou f, proto jsme ho zakomentovali. Problém je v tom, že v tomto případě vyjde desetinné číslo, které se snažíme uložit do čísla celého (int). Výstup programu je poté následující:

Konzolová aplikace
2
2
2.5
2.5
2.5

Vidíme, že výsledek dělení je někdy celočíselný a někdy reálný. Přitom vůbec nezáleží 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 vrátí vždy zas 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 / 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# .NET, 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), když chcete např. vybarvit šachovnici, zjistit odchylku vaší pozice od nějaké čtvercové sítě a podobně.

V C# .NET a obecně v céčkových jazycích zapíšeme modulo jako %:

Console.WriteLine(5 % 2); // Vypíše 1

Tak to bychom měli. V kurzu Základní konstrukce jazyka C# zájemci naleznou ještě několik dalších článků a příkladů k procvičení. Seriál nyní pokračuje v sekci Základy objektově orientovaného programování v C#. Příště si tedy představíme objektový svět a pochopíme mnoho věcí, které nám až doteď byly utajovány :) Určitě si zkuste cvičení, obsahuje nějaké věci s konzolí, co jsme si neukazovali a zajímavé projekty.


 

Stáhnout

Staženo 780x (22.28 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
16 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Miniatura
Předchozí článek
Vícerozměrná pole v C# .NET
Miniatura
Všechny články v sekci
Základní konstrukce jazyka C#
Miniatura
Následující článek
Cvičení k 11.-12. lekci C# .NET
Aktivity (11)

 

 

Komentáře
Zobrazit starší komentáře (7)

Avatar
Matej Rástocký:20.8.2015 22:13

Prepáčte asi mi niečo uniklo, ale keď napíšem hneď ten 1vý kód z číslom Pi a E,

Console.WriteLine("Pi: {0} \ne: {1}", Math.PI, Math.E);
Console.ReadKey();

Console.ReadKey();

vypíše mi to chybu: The type or namespace name 'PI' does not exist in the namespace 'Math' (are you missing an assembly reference?) Math C:\Users\rasto\O­neDrive\Projec­ts_C#\2015\Con­sole\Math\Mat­h\Program.cs
A to isté aj pre číslo E

Mohol by mi to prosím niekto vysvetliť ? :)

 
Odpovědět 20.8.2015 22:13
Avatar
Odpovídá na Matej Rástocký
Matej Rástocký:20.8.2015 23:01

už netreba funguje to :D prepáčte za planý poplach

 
Odpovědět 20.8.2015 23:01
Avatar
Jakub Jusko
Člen
Avatar
Jakub Jusko:25.2.2016 20:34

Ahoj, jde nějak ošetřit, aby program na výstupu házel zlomky místo des. čísel? Díky

 
Odpovědět 25.2.2016 20:34
Avatar
vovce
Člen
Avatar
vovce:9. února 11:31

V článku je opravdu chyba, klasické round funguje jako
Math.Round(-3.45, 1, MidpointRoundin­g.ToEven) = -3,4 (stejné jako Math.Round(-3,45,1) ) zaokrouhluje na nejbližší sudé číslo, je to podle standardu
zde

Math.Round(-3.45, 1, MidpointRoundin­g.AwayFromZero) = -3,5 takto vypadá klasické zaokrouhlování jak jej známe ze školy

Math.Round(3.45, 1, MidpointRoundin­g.ToEven) = 3,4
Math.Round(3.45, 1, MidpointRoundin­g.AwayFromZero) = 3,5

 
Odpovědět 9. února 11:31
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na vovce
David Čápka:9. února 12:07

Z dokumentace:

Because of the loss of precision that can result from representing decimal values as floating-point numbers or performing arithmetic operations on floating-point values, in some cases the Round(Double) method may not appear to round midpoint values to the nearest even integer. In the following example, because the floating-point value .1 has no finite binary representation, the first call to the Round(Double) method with a value of 11.5 returns 11 instead of 12.

Nevychází mi z toho, že by to mělo zaokrouhlovat schválně dolů, ale že se to občas stane kvůli tomu, jak jsou čísla vnitřně reprezentovaná.

Odpovědět 9. února 12:07
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
vovce
Člen
Avatar
Odpovídá na David Čápka
vovce:9. února 12:56

S tou reprezentací čísla máš určitě pravdu, ale co jsem pochopil ze článku je, že Math.Round se snaží defaultně zaokrouhlit k nejbližšímu sudému číslu. A také zaleží na datovém typu zaokrouhlované hodnoty.
Př:
u decimal

Math.Round(2.135m, 2); = 2,14
Math.Round(2.125m, 2); = 2,12
Math.Round(2.135m, 2, MidpointRounding.ToEven); = 2,14
Math.Round(2.125m, 2, MidpointRounding.ToEven); = 2,12
Math.Round(2.135m, 2, MidpointRounding.AwayFromZero); = 2,14
Math.Round(2.125m, 2, MidpointRounding.AwayFromZero); = 2,13

u float

Math.Round(2.135f, 2); = 2,13
Math.Round(2.125f, 2); = 2,12
Math.Round(2.135f, 2, MidpointRounding.ToEven); =2,13
Math.Round(2.125f, 2, MidpointRounding.ToEven); =2,12
Math.Round(2.135f, 2, MidpointRounding.AwayFromZero); = 2,13
Math.Round(2.125f, 2, MidpointRounding.AwayFromZero); = 2,13
Editováno 9. února 12:57
 
Odpovědět 9. února 12:56
Avatar
Libor Burda
Člen
Avatar
Libor Burda:21. dubna 10:55

Ahoj, když jsem si projekt pojmenoval Math, tak mi třída Math v takovém projektu nefungovala. Jsou nějaké podmínky pro pojmenování projektu?

 
Odpovědět 21. dubna 10:55
Avatar
Odpovídá na Libor Burda
Michal Štěpánek:21. dubna 11:09

Podmínky asi nejsou, ale je asi "nešťastné", neřkuli hloupé, zvolit si název projektu a cokoliv pojmenovávat "klíčovými slovy", které se v programování běžně používají. Jak má pak chudák program vědět, kdy tím slovem myslíš název čehokoliv, nebo nějakou třídu?

Odpovědět 21. dubna 11:09
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Libor Burda
Člen
Avatar
Odpovídá na Michal Štěpánek
Libor Burda:21. dubna 11:20

Díky za info - dalo se to předpokládat.

 
Odpovědět  +1 21. dubna 11:20
Avatar
Honza Rada
Člen
Avatar
Honza Rada:5. května 14:27

Super seriál díky němu jsem se naučil základy C#.NET mnohokrát ďěkuju

Odpovědět 5. května 14:27
#c#
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 17. Zobrazit vše