logo

Błąd zmiennoprzecinkowy w Pythonie

Python, powszechnie używany język programowania, doskonale radzi sobie z obliczeniami numerycznymi, nie jest jednak odporny na wyzwania stawiane przez arytmetykę zmiennoprzecinkową. Liczby zmiennoprzecinkowe w Pythonie są przybliżeniami liczb rzeczywistych, co prowadzi do błędy zaokrągleń, utrata precyzji i anulowania co może zaburzyć obliczenia. Możemy wykryj te błędy, szukając dziwnych wyników i posługiwanie się narzędziaminumpy.finfo>Do monitorować precyzję . Przy odrobinie ostrożności i sprytnych sztuczek nam się to uda kontroluj te błędy i upewnij się, że nasze obliczenia w języku Python są wiarygodne. W tym artykule zbadamy zawiłości błędów zmiennoprzecinkowych w Pyton .

Co to są liczby zmiennoprzecinkowe?

Liczby zmiennoprzecinkowe to skuteczny sposób przedstawiania liczb rzeczywistych w komputerach. Składają się z trzech części:



  • Istotne: Rzeczywiste cyfry reprezentujące liczbę (np. 3,14159)
  • Wykładnik potęgowy: Informuje o ile miejsc należy przesunąć znacznik w lewo lub w prawo (np. -2 w 3,14159 x 10^-2)
  • Baza: Zwykle 2 w przypadku komputerów, określające sposób wewnętrznej reprezentacji liczb

Dlaczego występują błędy zmiennoprzecinkowe?

Błędy zmiennoprzecinkowe powstają, ponieważ komputery przechowują liczby rzeczywiste przy użyciu skończonej liczby bitów, co prowadzi do przybliżeń i potencjalnych niedokładności. Liczby zmiennoprzecinkowe mają wewnętrzne ograniczenia:

  • Skończona precyzja: W znaczniku prowadzącym do można zapisać tylko ograniczoną liczbę cyfr błędy zaokrągleń podczas przedstawiania dokładnych miejsc po przecinku.
  • Utrata precyzji: Operacje takie jak dodawanie lub odejmowanie mogą jeszcze bardziej zmniejszyć precyzję, potęgując efekt zaokrąglenia.
  • Niedomiar/przelew: Bardzo małe lub duże liczby mogą wypaść poza reprezentowalny zakres, co prowadzi do niedomiar (staje się zerem) lub przelewowy (staje się nieskończonością).

Rodzaje błędów zmiennoprzecinkowych

a) Błędy zaokrągleń: Najczęściej spotykany, gdy należy przybliżyć dokładny ułamek dziesiętny, aby dopasować go do ograniczonej precyzji liczby zmiennoprzecinkowej.

b) Utrata precyzji: W kolejnych operacjach mogą stopniowo kumulować się błędy zaokrągleń, co prowadzi do znacznych niedokładności w wyniku końcowym.



c) Katastrofalne anulowanie: Podczas odejmowania prawie równych liczb o przeciwnych znakach ich cyfry znaczące znoszą się, pozostawiając mały i niedokładny wynik.

d) Przepełnienie/Niedomiar: Występują one, gdy obliczenia przekraczają reprezentowalny zakres wartości zmiennoprzecinkowych, co prowadzi do niedokładnych lub pozbawionych znaczenia wyników.

Wykrywanie błędów zmiennoprzecinkowych

  1. Obserwowanie nieoczekiwanych wyników: Porównywanie obliczonych wartości z oczekiwanymi wynikami lub wizualizacja danych może ujawnić niespójności, często spowodowane błędami.
  2. Korzystanie z bibliotek takich jak numpy.finfo> : Biblioteki lubiąnumpy>zapewnić narzędzia takie jakfinfo>aby sprawdzić precyzję i ograniczenia różnych typów danych zmiennoprzecinkowych.

Błąd zmiennoprzecinkowy Pythona

Tutaj omówimy różne typy przykładów ilustrujących błędy zmiennoprzecinkowe w Pythonie:



Utrata precyzji w konwersji dziesiętnej na binarną

W tym przykładzie liczba dziesiętna 0,1 jest konwertowana na liczbę binarną. Ze względu na nieskończone rozwinięcie binarne 0,1 używana jest tylko skończona liczba bitów, co prowadzi do utraty precyzji.

Python3




decimal_number>=> 0.1> binary_representation>=> format>(decimal_number,>'.30f'>)># 30 decimal places> print>(f>'Decimal: {decimal_number} Binary: {binary_representation}'>)>

>

ciąg zastępuje Java
>

Wyjście:

Decimal: 0.1 Binary: 0.100000000000000005551115123126>

Błędy zaokrąglania

W tym przypadku oczekuje się, że wynik trzykrotnego dodania 1/3 wyniesie 1,0. Jednakże ze względu na błędy zaokrągleń w przedstawianiu 1/3 suma może nie wynosić dokładnie 1,0.

Python3




result>=> 1.0> /> 3.0> sum_result>=> result>+> result>+> result> print>(f>'Expected Result: 1.0 Actual Result: {sum_result}'>)>

>

>

Wyjście:

Expected Result: 1.0 Actual Result: 1.0>

Błędy skumulowane w obliczeniach iteracyjnych

Ten przykład pokazuje, jak mogą wystąpić kumulujące się błędy w obliczeniach iteracyjnych. Dodanie 0,1 dziesięciokrotnie może nie dać dokładnego wyniku 1,0 ze względu na ograniczenia precyzji zmiennoprzecinkowej.

Python3




total>=> 0.0> for> i>in> range>(>10>):> >total>+>=> 0.1> print>(f>'Expected Result: 1.0 Actual Result: {total}'>)>

>

>

Wyjście:

Expected Result: 1.0 Actual Result: 0.9999999999999999>

Problemy z porównaniem

W takim przypadku porównanie sumy 0,1 i 0,2 do 0,3 może nie dać oczekiwanego rezultatuTrue>wynik wynikający z nieodłącznej niedokładności liczb zmiennoprzecinkowych.

Python3




a>=> 0.1> +> 0.2> b>=> 0.3> print>(f>'a: {a} b: {b} Equal: {a == b}'>)>

>

>

Wyjście:

a: 0.30000000000000004 b: 0.3 Equal: False>

Nieoczekiwane wyniki w obliczeniach

Tutaj odejmowanie1e16>od sumy(1e16 + 1)>oczekuje się, że zwróci 1, ale ze względu na błędy zmiennoprzecinkowe wynik może nie wynosić dokładnie 1.

Python3

if else instrukcja w Javie




a>=> 0.1> +> 0.2> b>=> 0.3> print>(f>'a: {a} b: {b} Equal: {a == b}'>)>

>

>

Wyjście:

Expected Result: 1 Actual Result: 0.0>

Zrozumienie precyzji zmiennoprzecinkowej

Tutaj zrozumiemy precyzję zmiennoprzecinkową: Anomalia 1.2 – 1.0 w Pythonie-

Wyzwania reprezentacyjne

Jak wiadomo 1,2 – 1,0 = 0,2. Ale gdy spróbujesz zrobić to samo w Pythonie, będziesz zaskoczony wynikami:

>>> 1,2 - 1,0>

Wyjście:

0.199999999999999996>

Można to uznać za błąd w Pythonie, ale tak nie jest. Ma to niewiele wspólnego z Pythonem, a znacznie więcej ze sposobem, w jaki podstawowa platforma obsługuje liczby zmiennoprzecinkowe. Jest to normalny przypadek występujący podczas wewnętrznej obsługi liczb zmiennoprzecinkowych w systemie. Jest to problem powstający podczas wewnętrznej reprezentacji liczb zmiennoprzecinkowych, która wykorzystuje stałą liczbę cyfr binarnych do przedstawienia liczby dziesiętnej. Trudno jest przedstawić niektóre liczby dziesiętne w formacie binarnym, dlatego w wielu przypadkach prowadzi to do małych błędów zaokrągleń. Znamy podobne przypadki w matematyce dziesiętnej, wielu wyników nie można przedstawić za pomocą ustalonej liczby cyfr dziesiętnych, na przykład Przykład

10 / 3 = 3.33333333.......>

W tym przypadku, biorąc za przykład 1,2, reprezentacja 0,2 w formacie binarnym to 0,00110011001100110011001100… i tak dalej. Trudno jest wewnętrznie przechowywać tę nieskończoną liczbę dziesiętną. Zwykle wartość obiektu zmiennoprzecinkowego jest przechowywana w binarnej liczbie zmiennoprzecinkowej ze stałą precyzją ( zazwyczaj 53 bity ). Więc reprezentujemy 1.2 wewnętrznie jako,

1.0011001100110011001100110011001100110011001100110011>

Co jest dokładnie równe:

1.1999999999999999555910790149937383830547332763671875>

Obsługa błędu zmiennoprzecinkowego

Tutaj omówimy inny przykład obsługi błędów zmiennoprzecinkowych w Pythonie:

Zaokrąglanie do określonego miejsca po przecinku

Zaokrąglając wynik do określonego miejsca po przecinku (np. 2), można złagodzić wpływ małych błędów zmiennoprzecinkowych.

Python3




result>=> 1.2> -> 1.0> rounded_result>=> round>(result,>2>)> print>(f>'Original Result: {result} Rounded Result: {rounded_result}'>)>

>

>

Wyjście:

Original Result: 0.19999999999999996 Rounded Result: 0.2>

Używanie klasy Decimal dla dużej precyzji

Thedecimal>moduł zapewniaDecimal>klasy, pozwalając na większą precyzję arytmetyki. Ustawianie precyzji za pomocągetcontext().prec>może pomóc w zarządzaniu precyzją konkretnych obliczeń

Python3

wyloguj się z konta Google na Androidzie




from> decimal>import> Decimal, getcontext> getcontext().prec>=> 4> # Set precision to 4 decimal places> result>=> Decimal(>'1.2'>)>-> Decimal(>'1.0'>)> print>(f>'High Precision Result: {result}'>)>

>

>

Wyjście:

High Precision Result: 0.2>

Używanie ułamków do dokładnych reprezentacji

Thefractions>moduł umożliwia pracę z dokładnymi reprezentacjami ułamkowymi, unikając błędów zmiennoprzecinkowych.

Python3




from> fractions>import> Fraction> result>=> Fraction(>'1.2'>)>-> Fraction(>'1.0'>)> print>(f>'Exact Fractional Result: {result}'>)>

>

>

Wyjście:

Exact Fractional Result: 1/5>

Obsługa wyników pośrednich w systemie dziesiętnym

UżyjDecimal>klasa do obliczeń pośrednich, aby zminimalizować skumulowane błędy przed konwersją z powrotem na float.

Python3




from> decimal>import> Decimal, getcontext> getcontext().prec>=> 6> # Set precision to 6 decimal places> intermediate_result>=> Decimal(>'1.2'>)>-> Decimal(>'1.0'>)> final_result>=> float>(intermediate_result)># Convert back to float if needed> print>(f>'Intermediate Result: {intermediate_result} Final Result: {final_result}'>)>

>

>

Wyjście:

Intermediate Result: 0.2 Final Result: 0.2>

Wniosek

Wciąż zastanawiasz się dlaczego Python nie rozwiązuje tego problemu w rzeczywistości nie ma to nic wspólnego z Pythonem. Dzieje się tak, ponieważ w ten sposób podstawowa platforma c obsługuje liczby zmiennoprzecinkowe, a ostatecznie ze względu na niedokładność zawsze będziemy zapisywać liczby jako ciąg o stałej liczbie cyfr. Należy zauważyć, że jest to zgodne z naturą binarnego zmiennoprzecinkowego: nie jest to błąd w tym programie Pyton Lub C i nie jest to również błąd w twoim kodzie. Zobaczysz ten sam rodzaj zachowań we wszystkich językach obsługujących arytmetykę zmiennoprzecinkową naszego sprzętu, chociaż niektóre języki mogą nie wyświetlać różnicy domyślnie lub we wszystkich trybach wyjściowych). Musimy wziąć pod uwagę to zachowanie, gdy naprawdę interesują nas problemy matematyczne wymagające dokładnej precyzji lub używając go w instrukcjach warunkowych. Sprawdzać zmiennoprzecinkowy sekcja w dokumentacji Pythona, aby zapoznać się z większą liczbą takich zachowań.

Często zadawane pytania (FAQ)

1. Co to jest błąd zmiennoprzecinkowy w Pythonie?

Błąd zmiennoprzecinkowy w Pythonie odnosi się do rozbieżności pomiędzy oczekiwanymi i rzeczywistymi wynikami podczas pracy z liczbami zmiennoprzecinkowymi, wynikającymi z ograniczeń reprezentowania liczb rzeczywistych w systemie binarnym.

2. Dlaczego 1.2 - 1.0> nie równe 0.2> w Pythonie?

Rozbieżność wynika z nieodłącznych wyzwań związanych z reprezentowaniem liczb dziesiętnych w formacie binarnym. Podczas wewnętrznej reprezentacji binarnej występują błędy zaokrągleń, co prowadzi do nieoczekiwanych wyników.

3. Czy błąd zmiennoprzecinkowy jest błędem w Pythonie?

Nie, to nie jest błąd w Pythonie. Jest to częsty problem w obliczeniach, związany ze sposobem wewnętrznej reprezentacji liczb zmiennoprzecinkowych. Python jest zgodny ze standardem IEEE 754 dotyczącym arytmetyki zmiennoprzecinkowej.

4. Jak mogę zaokrąglić wynik zmiennoprzecinkowy do określonego miejsca po przecinku?

Możesz skorzystać zround()>funkcja zaokrąglająca wynik zmiennoprzecinkowy do określonego miejsca po przecinku. Na przykład,rounded_result = round(result, 2)>.

5. Co to jest decimal> moduł i jak pomaga on w obsłudze błędów zmiennoprzecinkowych?

Thedecimal>moduł zapewniaDecimal>klasa dla arytmetyki o wyższej precyzji. Ustawianie precyzji i użytkowanieDecimal>może pomóc w ograniczeniu błędów zmiennoprzecinkowych.