Podobnie jak w innych językach, liczby w PHP są reprezentowane w systemie binarnym (system jedynek i zer), dlatego niektóre operacje matematyczne mogą dawać nieco inne wyniki niż te, których byśmy oczekiwali. Ta strona zawiera przegląd zachowań obliczeń w różnych kontekstach. Do zrozumienia tego zagadnienia wymagana jest przynajmniej podstawowa znajomość **technik numerycznych** i **systemów liczbowych**.
Sposób reprezentacji liczb jest określany przez typ danych, na przykład liczba całkowita jest konwertowana bezpośrednio z kodu źródłowego z systemu dziesiętnego na binarny. Nie musimy się w ogóle martwić o przeliczanie liczb, wszystko odbywa się automatycznie.
Konsekwencją tego przekształcenia jest to, że maksymalna wartość liczby całkowitej jest określona przez liczbę bitów dostępnych w pamięci. W 32-bitowym PHP zakres ten wynosi od -2 147 483 648
do -2 147 483 647
(~ ± 2 miliardy), w 64-bitowym PHP zakres ten wynosi od -9 223 372 036 854 775 808
do -9 223 372 036 854 775 807
(~ ± 9 kwintylionów). Wartość maksymalną można zawsze uzyskać przez wywołanie stałej PHP_INT_MAX
.
Liczby dziesiętne są przechowywane w typie danych float, który ma ograniczoną precyzję, dlatego są one przechowywane wewnętrznie jako para liczb, które podlegają operacji matematycznej mantysa * (2^wykładnik)
. Praktyczną konsekwencją tego jest możliwość przechowywania stosunkowo dużej liczby (rzędu miliardów) w małej liczbie bitów, ale niezbyt dokładnie.
Konsekwencją użycia typu danych float jest to, że wynik obliczenia 1 - 0,9
nie jest dokładnie 0,1
.
Przykład z forum internetowego:
$x = 0.3;$y = 0.4;echo 0.7 - $x - $y; // drukuje -5,5511151231258E-17
Jeśli nieco skorygujemy te liczby:
$x = 6.5;$y = 7.5;echo 14.0 - $x - $y; // drukuje 0
Ogólnie rzecz biorąc, kwestia ta jest przedyskutowana w osobnym artykule na VTM.e15.cz: Dlaczego komputery mają problemy z liczbami dziesiętnymi lub ogólnie o punkcie zmiennoprzecinkowym w Wikipedii.
Ogólnie rzecz biorąc, dobrze jest zaokrąglić wynik po wykonaniu obliczeń lub w ogóle unikać liczb dziesiętnych. Na przykład zapisz cenę nie w koronach (np. 14,90), lecz w groszach (np. 1490), a następnie pracuj z nią dokładnie. Zaokrąglanie jest omówione w następnej części artykułu.
$a = 5;$b = 3;echo $a + $b;
W operacjach można stosować zwykłe konwencje matematyczne, które respektują pierwszeństwo operatorów zgodnie z zasadami matematyki (mnożenie ma pierwszeństwo przed dodawaniem itd.). Wartości można zapisywać bezpośrednio lub odczytywać za pomocą zmiennych.
Może to nie być oczywiste na pierwszy rzut oka, ale w przykładzie matematycznym nie jest zapisany znak równości (
=
). Wynika z tego, że można rozwiązywać tylko proste operacje binarne, które zawsze działają tylko zdwoma elementami
(nie licz równań, do tego trzeba użyć specjalistycznej biblioteki).
W kolumnie
wynik
wypisuję to, co jest drukowane z założeniem:
$a = 5;$b = 3;$c = 10;
Operacja | Znak | Znak słowami | Przykład pisania | Wynik |
---|---|---|---|---|
Dodawanie | + |
Plus | echo $a + $b; |
8 |
Odejmowanie | - |
Minus | echo $a - $b; |
2 |
mnożenie | * |
gwiazdka | echo $a * $b; |
15 |
podział | / |
ukośnik | echo $a / $b; |
1.666666666666667 |
nawiasy | ( ) |
nawiasy | echo $a + ($b * $c); |
35 |
Konkatenacja ciągów | . |
Kropka | echo $a . $b . $c; |
5310 |
Reszta po podziale | % |
Procent | echo $a % $b; |
2 |
dwa plusy | echo $a++; |
6 | ||
odjąć jeden | -- |
dwa minus | echo $a--; |
4 |
Moc | ** |
dwie gwiazdki | echo $a ** $b; |
125 |
Operator potęgi (podwójna gwiazdka) jest dostępny dopiero od PHP 7.1. W innych wersjach PHP musisz używać uniwersalnej funkcji
pow($a, $b)
.
Jeśli rozwiązujesz jakieś typowe zadanie obliczeniowe, najprawdopodobniej istnieje już odpowiednia funkcja bezpośrednio w PHP - oto ich przegląd.
Zwykłe zaokrąglanie jest wykonywane za pomocą funkcji round(), która ma 3 parametry:
round(5); // 5round(5.1); // 5round(5.4); // 5round(5.5); // 6round(5.8); // 6round(5483.47621, 2); // 5483.47round(5483.47621, -2); // 5500
Istnieje również funkcja floor() służąca do zaokrąglania w dół oraz funkcja ceil() służąca do zaokrąglania w górę.
Uwaga na typy danych!.
Wszystkie funkcje zaokrąglające zwracają wynik jako
float
, nawet jeśli wynik jest liczbą całkowitą.Jeśli chcesz traktować wynik jako liczbę całkowitą, ważne jest, aby nadpisać typ wyniku. Na przykład:
echo (int) round(3.14);
.
PHP pracuje z różnymi typami danych, na przykład w przypadku float może się łatwo zdarzyć, że wynik działania funkcji round()
nie jest liczbą o skończonym rozwinięciu dziesiętnym. Do listowania polecam użycie funkcji number_format()
, którą omawiam poniżej.
Są one używane do wielu różnych obliczeń i opierają się na okręgu jednostkowym. Są one używane na przykład do wykreślania okręgów, elips, przemieszczeń itp.
Oblicz kąt między punktami x
i y
. Konwersje współrzędnych kartezjańskich i biegunowych.
Na podstawie hiperboli jednostkowej. Ich definicje można łatwo opisać za pomocą porównań:
Są one wykorzystywane na przykład do generowania terenu i symulacji fizycznych.
Na podstawie hiperboli jednostkowej.
echo sin(30); // -0.98803162409286echo sin(deg2rad(30)); // 0.5echo cos(deg2rad(123)); // -0.54463903501503echo 1/tan(deg2rad(45)); // 1 (onen cotangens)echo sin(deg2rad(500)); // 0.64278760968654echo atan2(deg2rad(50), deg2rad(23)); // 1.1396575860761
Czasami może się zdarzyć, że będziemy musieli przetworzyć wyrażenie matematyczne jako ciąg znaków użytkownika, na przykład 5+2^(1+3/2)
.
Nie ma prostego sposobu na przetwarzanie takich danych w PHP, ale stworzyłem serię bibliotek, które zajmują się tym problemem.
Więcej szczegółów znajdziesz w osobnym artykule Kalkulator w PHP: Przetwarzanie wyrażenia matematycznego jako łańcucha.
Duże liczby i liczby dziesiętne są przechowywane w PHP jako zmiennoprzecinkowe (float), dodatkowo są one zaokrąglane do około 15 miejsc po przecinku, co czasami może być irytujące. Dlatego właśnie stworzono bibliotekę BCMath Arbitrary Precision Mathematics.
Liczby w tej bibliotece są reprezentowane jako stringi, więc nie są ograniczone niedokładnością float, ale wykonywane operacje są o kilka rzędów wielkości wolniejsze (ale i tak szybsze niż gdybyśmy sami zaprogramowali taką funkcję).
Na przykład, jeśli chcemy uzyskać pierwiastek kwadratowy z 2 do 3 miejsc po przecinku, wystarczy wywołać polecenie:
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:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | pl