PHP Manual
/
Matematika

Matematika v PHP

16. 02. 2020

Obsah článku

Stejně jako v ostatních jazycích, tak i v PHP jsou čísla reprezentována ve dvojkové soustavě (soustava jedniček a nul), při některých matematických operacích proto může vycházet lehce odlišný výsledek, než bychom čekali. Tato stránka obsahuje přehled chování výpočtů v různých kontextech. Pro pochopení je potřeba aspoň základní znalost **číslicové techniky** a **číselných soustav**.

Reprezentace čísel v paměti

Způsob reprezentace čísel charakterizuje datový typ, například integer je převeden přímo ze zdrojového kódu z desítkové soustavy na dvojkovou (binární). O převod čísel se nemusíme vůbec starat, vše probíhá automaticky.

Důsledek tohoto převodu je, že maximální hodnota integeru (celé číslo) je určena podle počtu dostupných bitů v paměti. Na 32-bitovém PHP je rozsah od -2,147,483,648 do 2,147,483,647 (~ ± 2 miliardy), 64-bitové PHP má rozsah od -9,223,372,036,854,775,808 do 9,223,372,036,854,775,807 (~ ± 9 quintillionů). Maximální hodnotu můžeme vždy získat zavoláním konstanty PHP_INT_MAX.

Desetinná čísla se ukládají do datového typu float, který má omezenou přesnost, proto se interně ukládá jako dvojice čísel, které podléhají matematické operaci mantisa * (2 ^ exponent). Praktický důsledek je ten, že jsme schopni na malé množství bitů uložit i relativně velké číslo (v řádu miliard), akorát ne příliš přesně.

Důsledek použití datového typu float je, že výsledkem výpočtu 1 - 0.9 není přesně 0.1.

Příklad z webového fóra:

$x = 0.3;
$y = 0.4;
echo 0.7 - $x - $y; // vypíše -5.5511151231258E-17

Pokud ovšem čísla lehce upravíme:

$x = 6.5;
$y = 7.5;
echo 14.0 - $x - $y; // vypíše 0

Obecně o této problematice pojednává samostatný článek na webu VTM.e15.cz: Proč počítačům dělají problémy desetinná čísla, případně obecně o plovoucí řádové čárce na Wikipedii.

Obecně je dobré po výpočtu výsledek zaokrouhlit, nebo se desetinným číslům úplně vyhnout. Například cenu nebudeme ukládat v korunách (jako 14.90), ale v haléřích (jako 1490) a poté s ní pracovat přesně. O zaokrouhlování pojednává další kapitola článku.

Matematické operace

$a = 5;
$b = 3;
echo $a + $b;

Pro operace lze použít běžné matematické zvyklosti, při kterých se respektuje přednost operátorů podle pravidel matematiky (násobení má přednost před sčítáním a podobně). Hodnoty lze zapsat přímo, nebo je načítat přes proměnné.

Možná to není na první pohled zřejmé, ale u matematického příkladu se nezapisuje znak rovnítka (=). Z toho tedy vyplývá, že lze řešit jen jednoduché binární operace, které vždy pracují jen s dvěma prvky (s rovnicemi nepočítejte, na to se musí použít specializovaná knihovna).

Přehled základních operátorů

Ve sloupci výsledek uvádím, co se vypíše za předpokladu, že:

$a = 5;
$b = 3;
$c = 10;

Operace Značka Značka slovně Příklad zápisu Výsledek
Sčítání + Plus echo $a + $b; 8
Odčítání - Mínus echo $a - $b; 2
Násobení * Hvězdička echo $a * $b; 15
dělení / Lomítko echo $a / $b; 1.66666666667
Závorky ( ) Závorky echo $a + ($b * $c); 35
Spojování řetězců . Tečka echo $a . $b . $c; 5310
Zbytek po dělení % Procento echo $a % $b; 2
Přičtení jedničky ++ dva plusy echo $a++; 6
Odečtení jedničky -- dva mínusy echo $a--; 4
Mocnina ** dvě hvězdičky echo $a ** $b; 125

Operátor mocniny (dvojitá hvězdička) je dostupný až od PHP 7.1. V jiných verzí PHP je nutné použít univerzální funkci pow($a, $b).

Přehled základních matematických funkcí

Pokud řešíte nějaký běžný výpočetní úkol, tak s největší pravděpodobností již existuje funkce přímo v PHP, zde je jejich komentovaný přehled.

Zaokrouhlování

Běžné zaokrouhlení se provádí funkcí round(), má 3 parametry:

  • Zaokrouhlované číslo
  • Nepovinný: Přesnost (na kolik desetinných míst)
  • Nepovinný: Půlící hodnota (od jaké hodnoty se má zaokrouhlovat nahoru)

round(5); // 5
round(5.1); // 5
round(5.4); // 5
round(5.5); // 6
round(5.8); // 6
round(5483.47621, 2); // 5483.47
round(5483.47621, -2); // 5500

Dále existuje funkce floor() pro zaokrouhlení směrem dolů a funkce ceil() pro směr nahoru.

Pozor na datové typy!

Všechny zaokrouhlovací funkce vrací výsledek jako float a to i v případě, že je výsledkem celé číslo.

Pokud chceme s výsledkem pracovat jako s celým číslem, je důležité ho ještě dodatečně přetypovat. Například: echo (int) round(3.14);

PHP pracuje s různými datovými typy, například u floatu se může snadno stát, že výsledkem funkce round() nebude číslo s konečným desetiným rozvojem. Pro výpis doporučuji použít funkci number_format(), o které pojednávám níže.

Goniometrické funkce

Používají se na hodně různých výpočtů a vychází z jednotkové kružnice. Využití je například při vykreslování kružnic, elips, posunů a podobně.

Cyklometrické funkce

Výpočet úhlu z x a y. Převody kartézských a polárních souřadnic.

Hyperbolické funkce

Vychází z jednotkové hyperboly. Jejich definice lze jednoduše popsat pomocí přirovnání:

  • Elipsa, Kružnice, Kružnice s poloměrem 1
  • Hyperbola, Rovnoosá hyperbola, Jednotková hyperbola

Používají se například při generování terénu a fyzikální simulace.

Hyperbolometrické funkce

Vychází z jednotkové hyperboly.

Příklady použití goniometrických funkcí

echo sin(30); // -0.98803162409286
echo sin(deg2rad(30)); // 0.5
echo cos(deg2rad(123)); // -0.54463903501503
echo 1/tan(deg2rad(45)); // 1 (onen cotangens)
echo sin(deg2rad(500)); // 0.64278760968654
echo atan2(deg2rad(50), deg2rad(23)); // 1.1396575860761

Kalkulačka - zpracování matematického výrazu

Někdy se může stát, že budeme potřebovat zpracovat matematický výraz jako uživatelský řetězec, tedy třeba 5+2^(1+3/2).

V PHP neexistuje jednoduchý způsob, jak takový vstup zpracovat, ale naprogramoval jsem sérii knihoven, které tuto problematiku řeší.

Podrobnosti si přečtěte v samostatném článku Kalkulačka v PHP: Zpracování matematického výrazu jako řetězec.

Operace s velkými čísly a přesnost výpočtů

Velká čísla a desetinná čísla se v PHP ukládají jako float, navíc se zaokrouhlují přibližně na 15 desetinných míst, což může být někdy nepříjemné. Proto vznikla knihovna BCMath Arbitrary Precision Mathematics.

Čísla se v této knihovně reprezentují jako string, proto nejsou limitovány nepřesností floatu, nicméně prováděné operace jsou o několik řádů pomalejší (ale stále jde o rychlejší způsob, než kdybychom si takovou funkci naprogramovali sami).

Pokud chceme získat například odmocninu ze 2 na 3 desetinná místa, tak stačí jen zavolat:

echo bcsqrt('2', 3); // 1.414

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
2.

Potřebujete poradit s PHP?

Nabízím trénink vývojářů, konzultace, školení a analýzu návrhových vzorů. Osobně v Praze nebo online.

Napište mi, pokud si nevíte rady.

Lektor: Jan Barášek

Status:
All systems normal.
2024