W naszym codziennym życiu jesteśmy otoczeni cenami i kwotami pieniędzy zapisanymi w formacie zmiennoprzecinkowym, takim jak 4,49 zł za mleko czy 199,99 zł za nowe buty. Wydaje się to być naturalnym rozwiązaniem, które ułatwia nam zarówno dokonywanie zakupów, jak i prowadzenie finansów osobistych. Jednak warto zastanowić się, dlaczego eksperci finansowi i programiści zdecydowanie odradzają trzymanie pieniędzy w formie zmiennoprzecinkowej (float) i skąd wynika problem z precyzją finansową.
Co to jest float?
Liczby zmiennoprzecinkowe, w skrócie float, są reprezentacją liczb rzeczywistych w komputerach. W przeciwieństwie do liczb całkowitych, które są reprezentowane dokładnie, liczby zmiennoprzecinkowe są przybliżone. Warto zrozumieć, że komputery używają systemu binarnego do przechowywania liczb zmiennoprzecinkowych. Dla przykładu, w systemie dziesiętnym liczba 0,1 ma nieskończoną liczbę miejsc po przecinku, a w systemie binarnym liczba 1/10 (czyli 0,1 w systemie dziesiętnym) jest reprezentowana jako nieskończony ciąg zer i jedynek.
Problem z precyzją
Głównym problemem wynikającym z reprezentacji float jest precyzja. Komputery mają ograniczoną liczbę bitów, które mogą być używane do przechowywania liczb zmiennoprzecinkowych. W efekcie, niektóre liczby dziesiętne nie mogą być dokładnie reprezentowane w systemie binarnym. 0,1 jest jednym z takich przykładów. Kiedy wykonujemy operacje matematyczne na takich przybliżonych liczbach, mogą wystąpić błędy zaokrągleń, co prowadzi do wyników, które nie są dokładne.
0.1 + 0.1 + 0.1 ≠ 0.3?
Dlaczego 0.1 + 0.1 + 0.1 nie jest równe 0.3? Jest to klasyczny przykład pochodzący z oficjalnej strony python.org. Komputer reprezentuje 0,1 w systemie binarnym jako nieskończony ciąg zer i jedynek, który jest tylko przybliżeniem 0,1. Kiedy dodajemy to przybliżone 0,1 do siebie trzy razy, otrzymujemy kolejne przybliżenia, które nie sumują się dokładnie do 0,3.
Dla komputera:
0.1 + 0.1 + 0.1 >> 0.30000000000000004
To jest wynik zaokrąglony, aby zmieścić się w ograniczonej ilości bitów.
Jak sobie radzić z tym problemem?
Radzenie sobie z problemem precyzji finansowej w Pythonie w dziedzinie data science jest kluczowe, szczególnie gdy pracujemy z dużymi danymi finansowymi lub przeprowadzamy analizy, które wymagają dokładnych obliczeń pieniężnych. Oto kilka praktycznych kroków, które można podjąć, aby zaradzić temu problemowi:
- Użyj odpowiednich typów danych: Zamiast używać typu float do przechowywania wartości pieniężnych, zaleca się używanie specjalnych typów danych, takich jak decimal. Ten typ danych pozwala na precyzyjne reprezentowanie wartości pieniężnych, eliminując błędy zaokrągleń związanego z float.
- Unikaj operacji na float: Staraj się unikać operacji matematycznych na liczbach float, szczególnie wrażliwych na precyzję, takich jak pieniądze. Zamiast tego używaj specjalnych funkcji i metod dostępnych w module decimal.
- Zmień złotówki na grosze. Zamiast trzymać 10 zł jako 10.0 (float), możesz trzymać tę samą kwotę jako 1000 groszy (int). To pozwala na bardziej precyzyjne obliczenia i uniknięcie błędów związanych z float. Jednak przy pracy z pieniędzmi w groszach ważne jest, aby odpowiednio obsługiwać konwersje pomiędzy groszami a złotówkami w zależności od potrzeb wyświetlania i raportowania wyników.
from decimal import Decimal amount1 = Decimal('100.10') amount2 = Decimal('200.20') result = amount1 + amount2