Wszystkie artykuły

IEEE 754: dlaczego 0.1 + 0.2 nie równa się 0.3 w kodzie

Otwórz konsolę C# (na przykład w .NET Interactive) i wpisz 0.1 + 0.2 — mimo że na ekranie zobaczysz skrócone 0.3, porównanie 0.1 + 0.2 == 0.3 zwróci false. To nie jest błąd konkretnego języka — to bezpośrednia konsekwencja tego, jak standard IEEE 754 reprezentuje liczby ułamkowe w systemie dwójkowym, a dokładnie ten sam problem pojawia się w JavaScript, Javie i Pythonie.

Trzy części liczby zmiennoprzecinkowej

Liczba według IEEE 754 jest przechowywana jako trzy składniki: znak (dodatni lub ujemny), mantysa (znaczące cyfry liczby) i wykładnik (potęga, o którą przesuwany jest przecinek). Przypomina to notację naukową: 1.5 × 10², tylko w systemie dwójkowym.

Dlaczego 0.1 nie da się dokładnie zapisać w systemie dwójkowym

0.1 w systemie dziesiętnym to nieskończony ułamek w systemie dwójkowym (podobnie jak 1/3 jest nieskończony w systemie dziesiętnym). Komputer przechowuje tylko ograniczoną liczbę bitów mantysy, więc liczba jest zaokrąglana do najbliższej możliwej wartości — i to właśnie to zaokrąglenie powoduje widoczny „błąd".

Gdzie to naprawdę szkodzi: suma koszyka zakupowego

Strona płatności, która sumuje ceny pozycji jako zwykłe liczby zmiennoprzecinkowe, może po wystarczającej liczbie produktów odbiegać o grosz od oczekiwanej sumy — każde dodawanie lekko zaokrągla, a błędy się kumulują zamiast się znosić. Dlatego systemy płatności zwykle liczą w groszach jako liczbach całkowitych albo używają dedykowanego typu decimal, zamiast sumować surowe wartości zmiennoprzecinkowe.

Do czego to się przydaje

  • Zrozumienie i zdiagnozowanie nieoczekiwanych błędów zaokrąglenia w obliczeniach finansowych lub naukowych.
  • Zobaczenie dokładnej binarnej reprezentacji konkretnej liczby zmiennoprzecinkowej.
  • Wytłumaczenie koledze lub studentowi, dlaczego porównywanie liczb ułamkowych pod kątem dokładnej równości to zła praktyka.

Liczby subnormalne blisko zera

Gdy wartość liczby jest zbyt mała dla standardowej reprezentacji (mantysa zaczynająca się od domyślnej jedynki), IEEE 754 przechodzi w tryb subnormalny (zdenormalizowany), w którym ta domyślna jedynka jest pomijana — pozwala to reprezentować jeszcze mniejsze co do wartości bezwzględnej liczby kosztem stopniowej utraty precyzji zamiast gwałtownego skoku do zera. To „łagodne" przejście do zera jest lepsze niż nagłe wyzerowanie, ale obliczenia subnormalne są zauważalnie wolniejsze od zwykłych na niektórych procesorach.

Wypróbuj narzędzie