4.1 Zaokrąglanie liczb zmiennoprzecinkowych
Liczby zmiennoprzecinkowe po angielsku nazywają się float
ing point number — liczby zmiennoprzecinkowe: w USA do oddzielenia części całkowitej od części ułamkowej używa się kropki. Stąd pochodzi nazwa float
.
Jak już mówiliśmy, przy konwersji liczby zmiennoprzecinkowej (float) na całkowitą (int), zawsze jest ona zaokrąglana w dół do liczby całkowitej — część ułamkowa jest po prostu odrzucana. Ale łatwo sobie wyobrazić sytuację, kiedy chcemy zaokrąglić liczbę ułamkową do najbliższej liczby całkowitej. Co robić w takiej sytuacji?
Do tego w Pythonie jest wbudowana funkcja round()
. Została wymyślona jeszcze przed stworzeniem biblioteki math, dlatego do niej nie należy. Funkcje zaokrąglania w dół i zaokrąglania do góry znajdują się w bibliotece math.
Funkcja round()
zaokrągla liczbę do najbliższej liczby całkowitej:
round(liczba_zmiennoprzecinkowa)
Działa tak, że zwróci liczbę całkowitą, do której bliżej jest podanej liczbie zmiennoprzecinkowej. Ważne jest, że jeśli część ułamkowa wynosi 0.5, funkcja round()
używa metody zaokrąglania do najbliższej parzystej liczby całkowitej. To się nazywa "bankowe zaokrąglanie" i pozwala zmniejszyć systematyczny błąd przy wielokrotnym zaokrąglaniu. Na przykład:
Przykłady:
Komenda | Wynik |
---|---|
x = round(4.1) | 4 |
x = round(4.5) | 4 |
x = round(4.9) | 5 |
x = round(5.5) | 6 |
Funkcja math.ceil()
zaokrągla liczbę do góry, przykłady:
Komenda | Wynik |
---|---|
x = math.ceil(4.1) | 5 |
x = math.ceil(4.5) | 5 |
x = math.ceil(4.9) | 5 |
Funkcja math.floor()
zaokrągla liczbę w dół, przykłady:
Komenda | Wynik |
---|---|
x = math.floor(4.1) | 4 |
x = math.floor(4.5) | 4 |
x = math.floor(4.9) | 4 |
Choć łatwiej zaokrąglić liczbę w dół, używając funkcji konwersji typów int()
:
Komenda | Wynik |
---|---|
x = int(4.9) | 4 |
Jeśli jest trudno zapamiętać te komendy, pomoże mała lekcja angielskiego:
math
— matematykaround
— okrąg/zaokrąglaćceiling
— sufitfloor
— podłoga
4.2 Organizacja liczb zmiennoprzecinkowych
Typ float
w Pythonie może przechowywać wartości w zakresie od -1.7*10308 do +1.7*10308. Taki ogromny zakres wartości wynika z tego, że typ float
działa zupełnie inaczej niż typy całkowite. Każda zmienna typu float zawiera dwie liczby: pierwsza to mantysa, a druga — wykładnik.
Załóżmy, że mamy liczbę 123456789, i zapisaliśmy ją w zmiennej typu float
. Wtedy liczba zostanie przekształcona do postaci 1.23456789*108, a wewnątrz typu float
będą przechowywane dwie liczby — 23456789 i 8. Czerwono zaznaczono „znaczącą część liczby” (mantysa), zielono — 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), a część bitów służy do przechowywania wykładnika (oraz znaku liczby i znaku wykładnika), maksymalna długość mantysy jest ograniczona do 15 cyfr.
To bardzo uproszczony opis działania liczb zmiennoprzecinkowych, bardziej pełny opis można znaleźc w Google.
4.3 Utrata precyzji przy pracy z liczbami zmiennoprzecinkowymi
Przy pracy z liczbami zmiennoprzecinkowymi zawsze trzeba pamiętać, że są one nieprecyzyjne. Zawsze będą błędy zaokrąglenia, błędy konwersji
z systemu dziesiętnego na binarny i, co najczęstsze — utraty precyzji
przy dodawaniu/odejmowaniu liczb o bardzo różnych wielkościach.
To ostatnie to najbardziej zaskakująca sytuacja dla początkujących programistów.
Jeżeli od liczby 109 odjąć 1/109, otrzymamy ponownie 109.
Odejmowanie liczb o bardzo różnych wielkościach | Wyjaśnienie |
---|---|
|
Druga liczba jest zbyt mała, a jej znacząca część jest ignorowana (zaznaczone na szaro). Pomarańczowo zaznaczone są 15 znaczących cyfr. |
Co tu mówić, programowanie to nie matematyka.
4.4 Niebezpieczeństwo porównywania liczb zmiennoprzecinkowych
Jeszcze jedno niebezpieczeństwo czeka programistów przy porównywaniu liczb zmiennoprzecinkowych. Ponieważ przy pracy z tymi liczbami mogą nawarstwiać się błędy zaokrąglenia, mogą pojawić się sytuacje, kiedy liczby zmiennoprzecinkowe powinny być równe, ale nie są. I odwrotnie: liczby powinny być nierówne, ale są równe.
Przykład:
Komenda | Wyjaśnienie |
---|---|
a = 1000000000.0 b = 0.000000001 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 podanym powyżej przykładzie a i c nie powinny być równe, ale są.
Albo weźmy inny przykład:
Komenda | Wyjaśnienie |
---|---|
a = 1.00000000000000001 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:
Bierze się jakąś bardzo małą wartość. Jeśli różnica liczb (moduł) jest mniejsza niż ta mała wartość, to uznaje się je za równe. Przykład:
a = 0.00000000012
b = 0.000000000011
if abs(a - b) < 0.00001:
print("równe")
else:
print("nie równe")
GO TO FULL VERSION