1.1 Zaokrąglanie liczb zmiennoprzecinkowych
Liczby zmiennoprzecinkowe po angielsku nazywane są floating point number – liczby z przecinkiem: w USA do oddzielenia części całkowitej od ułamkowej używa się kropki. Stąd nazwa float.
Jak już omówiliśmy, przy konwersji liczby zmiennoprzecinkowej (float) na całą (int), zawsze jest zaokrąglana w dół do całkowitej — część ułamkowa po prostu jest odrzucana. A przecież łatwo sobie wyobrazić sytuację, gdy liczba ułamkowa musi być zaokrąglona po prostu do najbliższego całkowitego lub nawet w górę. Co wtedy zrobić?
Na taką sytuację w JavaScript mamy wbudowaną funkcję round()
. Została stworzona jeszcze przed powstaniem biblioteki Math,
dlatego nie wchodzi w jej skład. Funkcje do zaokrąglania w dół i w górę znajdują się w bibliotece math.
Funkcja Math.round()
Funkcja Math.round()
zaokrągla liczbę do najbliższej całkowitej:
Math.round(liczba_zmiennoprzecinkowa)
Ta funkcja zwróci liczbę całkowitą, do której bliżej jest przekazana liczba zmiennoprzecinkowa.
Przykłady:
Komenda | Wynik |
---|---|
let x = Math.round(4.1); |
4 |
let x = Math.round(4.5); |
5 |
let x = Math.round(4.9); |
5 |
Funkcja Math.ceil()
Funkcja Math.ceil()
zaokrągla liczbę do najbliższej całkowitej w górę:
Komenda | Wynik |
---|---|
let x = Math.ceil(4.1); |
5 |
let x = Math.ceil(4.5); |
5 |
let x = Math.ceil(4.9); |
5 |
Funkcja Math.floor()
Funkcja Math.floor()
zaokrągla liczbę do najbliższej całkowitej w dół:
Komenda | Wynik |
---|---|
let x = Math.floor(4.1); |
4 |
let x = Math.floor(4.5); |
4 |
let x = Math.floor(4.9); |
4 |
Jeśli trudno ci zapamiętać te komendy, pomoże ci mała lekcja angielskiego:
- math — matematyka
- round — okrąg/zaokrąglać
- ceiling — sufit
- floor — podłoga
1.2 Struktura liczb zmiennoprzecinkowych
Typ number w JavaScript może przechowywać wartości w zakresie od -1.7*10308 do +1.7*10308. Takie ogromne wartości wynikają z faktu, że typ number jest zbudowany całkowicie inaczej w porównaniu z typami całkowitymi. Każda zmienna typu number zawiera dwie liczby: pierwsza nazywa się mantysa, a druga — wykładnik.
Załóżmy, że mamy liczbę 123456789, i zapisaliśmy ją w zmiennej typu number. Wówczas liczba zostanie przekształcona do postaci 1.23456789*108, a wewnątrz typu number będą przechowywane liczby — 1.23456789 i 8. Na czerwono zaznaczono „znaczącą część liczby” (mantysę), na niebiesko — wykładnik.
Takie podejście pozwala przechowywać zarówno bardzo duże liczby, jak i bardzo małe. Ale ponieważ rozmiar liczby jest ograniczony do 8 bajtów (64 bitów) i część bitów jest wykorzystywana na przechowywanie wykładnika (a także znaku liczby i znaku wykładnika), maksymalna długość mantysy jest ograniczona do 15 cyfr.
To bardzo uproszczony opis struktury liczb zmiennoprzecinkowych: bardziej szczegółowe można znaleźć pod tym linkiem.
1.3 Utrata dokładności przy pracy z liczbami zmiennoprzecinkowymi
Pracując z liczbami zmiennoprzecinkowymi, zawsze musisz mieć na uwadze, że liczby zmiennoprzecinkowe są niedokładne. Zawsze będą błędy zaokrąglenia, błędy konwersji z systemu dziesiętnego na binarny, i wreszcie najczęstsze — utrata dokładności przy dodawaniu/odejmowaniu liczb o bardzo różnej skali.
Ostatnie to najbardziej zaskakująca sytuacja dla początkujących w programowaniu.
Jeśli odejmujesz od liczby 109 1/109, dostaniesz z powrotem 109.
Odejmowanie liczb o bardzo różnej skali | Wyjaśnienie |
---|---|
1000000000.000000000 - 0.000000001 1000000000.000000000 |
Druga liczba jest zbyt mała i jej znacząca część jest pomijana (zaznaczono na szaro). Na czerwono zaznaczono 15 znaczących cyfr. |
Co tu dużo mówić, programowanie to nie matematyka.
1.4 Niebezpieczeństwo porównywania liczb zmiennoprzecinkowych
Kolejne niebezpieczeństwo czyha na programistów przy porównywaniu liczb zmiennoprzecinkowych. Ponieważ przy pracy z tymi liczbami mogą się gromadzić błędy zaokrąglenia, mogą wystąpić sytuacje, gdy liczby zmiennoprzecinkowe powinny być równe, ale nie są. I odwrotnie: liczby powinny być różne, a są równe.
Przykład:
Komenda | Wyjaśnienie |
---|---|
let a = 1000000000.0 let b = 0.000000001 let c = a – b
|
W zmiennej a będzie wartość 1000000000.0 .W zmiennej c będzie wartość 1000000000.0 (liczba w zmiennej b jest zbyt mała).
|
W powyższym przykładzie a
i c
nie powinny być równe, ale są.
Albo inny przykład:
Komenda | Wyjaśnienie |
---|---|
let a = 1.00000000000000001 let b = 1.00000000000000002
|
W zmiennej a będzie wartość 1.0 .W zmiennej b będzie wartość 1.0 .
|
W praktyce liczby zmiennoprzecinkowe porównuje się tak:
Jeśli różnica liczb (moduł) jest mniejsza niż jakaś bardzo mała liczba, są one uważane za równe.
Przykład:
let a = 0.00000000012;
let b = 0.000000000011;
if (Math.abs(a - b) < 0.00001) {
console.log("równy");
} else {
console.log("nie równy");
}
GO TO FULL VERSION