logo

Flyttalsfel i Python

Python, ett flitigt använt programmeringsspråk, utmärker sig i numeriska beräkningsuppgifter, men det är inte immunt mot de utmaningar som flyttalsaritmetik innebär. Flyttal i Python är approximationer av reella tal, vilket leder till avrundningsfel, förlust av precision och annulleringar som kan kasta ut beräkningar. Vi kan upptäck dessa fel genom att leta efter konstiga resultat och använda verktygnumpy.finfo>till övervaka precision . Med lite försiktighet och smarta knep kan vi hålla dessa fel i schack och se till att våra Python-beräkningar är tillförlitliga. I den här artikeln kommer vi att utforska krångligheterna med flyttalsfel i Pytonorm .

Vad är flyttal?

Flyttal är ett effektivt sätt att representera reella tal i datorer. De består av tre delar:



  • Signifikant: De faktiska siffrorna som representerar numret (t.ex. 3,14159)
  • Exponent: Anger hur många ställen som signifikanden ska flyttas åt vänster eller höger (t.ex. -2 i 3,14159 x 10^-2)
  • Bas: Typiskt 2 för datorer, bestämmer hur siffror representeras internt

Varför uppstår flyttalsfel?

Flyttalsfel uppstår eftersom datorer lagrar reella tal med ett ändligt antal bitar, vilket leder till approximationer och potentiella felaktigheter. Flyttal har inneboende begränsningar:

  • Ändlig precision: Endast ett begränsat antal siffror kan lagras i signifikanden, vilket leder till avrundningsfel när de representerar exakta decimaler.
  • Förlust av precision: Operationer som addition eller subtraktion kan ytterligare minska precisionen och förvärra effekterna av avrundning.
  • Underflöde/Bräddavlopp: Extremt små eller stora antal kan falla utanför det representativa intervallet, vilket leder till underflöde (blir noll) eller svämma över (blir oändlighet).

Typer av flyttalsfel

a) Avrundningsfel: Det vanligaste, inträffar när en exakt decimal måste approximeras för att passa den begränsade precisionen hos ett flytande.

b) Förlust av precision: Efterföljande operationer kan gradvis ackumulera avrundningsfel, vilket leder till betydande felaktigheter i slutresultatet.



c) Katastrofal avbokning: När man subtraherar nästan lika siffror med motsatta tecken, tas deras signifikanta siffror ut och lämnar ett litet och felaktigt resultat.

d) Bräddavlopp/underflöde: Dessa inträffar när beräkningar överskrider det representativa intervallet för flytvärden, vilket leder till felaktiga eller meningslösa resultat.

Upptäcker flyttalsfel

  1. Att observera oväntade resultat: Att jämföra beräknade värden med förväntade utfall eller visualisera data kan avslöja inkonsekvenser som ofta orsakas av fel.
  2. Använda bibliotek som numpy.finfo> : Bibliotek somnumpy>tillhandahålla verktyg somfinfo>för att kontrollera precisionen och begränsningarna för olika flytdatatyper.

Python Flytpunktsfel

Här kommer vi att diskutera olika typer av exempel som illustrerar flyttalsfel i Python:



Förlust av precision i decimal till binär omvandling

I det här exemplet omvandlas decimaltalet 0,1 till binärt. På grund av den oändliga binära expansionen på 0,1 används endast ett ändligt antal bitar, vilket leder till en förlust av precision.

Python3




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

>

>

Produktion:

Decimal: 0.1 Binary: 0.100000000000000005551115123126>

Avrundningsfel

Här förväntas resultatet av tillägget av 1/3 tre gånger bli 1,0. Men på grund av avrundningsfel när det representerar 1/3, kanske summan inte är exakt 1,0.

Python3




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

>

>

Produktion:

Expected Result: 1.0 Actual Result: 1.0>

Ackumulativa fel i iterativa beräkningar

Det här exemplet visar hur ackumulerande fel kan uppstå i iterativa beräkningar. Att lägga till 0,1 tio gånger kanske inte ger ett exakt resultat på 1,0 på grund av flyttalsprecisionsbegränsningar.

Python3




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

>

>

Produktion:

Expected Result: 1.0 Actual Result: 0.9999999999999999>

Jämförelsefrågor

I det här fallet kan det hända att en jämförelse av summan av 0,1 och 0,2 till 0,3 inte ger det förväntadeTrue>resultat på grund av den inneboende oprecisionen i flyttalstal.

Python3




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

>

>

Produktion:

a: 0.30000000000000004 b: 0.3 Equal: False>

Oväntade resultat i beräkningar

Här, subtraktionen av1e16>från summan(1e16 + 1)>förväntas ge 1, men på grund av flyttalsfel kanske resultatet inte blir exakt 1.

Python3




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

>

>

Produktion:

Expected Result: 1 Actual Result: 0.0>

Förstå Floating-Point Precision

Här kommer vi att förstå flyttalsprecisionen: 1.2 – 1.0 Anomaly i Python-

Representationsutmaningar

Som det är känt att 1,2 – 1,0 = 0,2. Men när du försöker göra samma sak i Python kommer du att förvånas över resultaten:

>>> 1,2 - 1,0>

Produktion:

0.199999999999999996>

Detta kan betraktas som en bugg i Python, men det är det inte. Detta har lite att göra med Python och mycket mer att göra med hur den underliggande plattformen hanterar flyttal. Det är ett normalt fall när man hanterar flyttal internt i ett system. Det är ett problem som orsakas när den interna representationen av flyttalstal, som använder ett fast antal binära siffror för att representera ett decimaltal. Det är svårt att representera några decimaltal i binärt, så i många fall leder det till små avrundningsfel. Vi känner till liknande fall i decimal matematik, många resultat kan inte representeras med ett fast antal decimalsiffror, för Exempel

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

I det här fallet, med 1,2 som exempel, är representationen av 0,2 i binär 0,00110011001100110011001100…… och så vidare. Det är svårt att lagra detta oändliga decimaltal internt. Normalt lagras ett flytobjekts värde i binärt flyttal med en fast precision ( vanligtvis 53 bitar ). Så vi representerar 1.2 internt som,

1.0011001100110011001100110011001100110011001100110011>

Vilket är exakt lika med:

1.1999999999999999555910790149937383830547332763671875>

Hantering av flytpunktsfel

Här kommer vi att diskutera olika exempel på hur man hanterar flyttalsfel i Python:

Avrundning till en specifik decimal

Genom att avrunda resultatet till en specifik decimal (t.ex. 2) kan du mildra effekten av små flyttalsfel.

Python3




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

>

>

Produktion:

Original Result: 0.19999999999999996 Rounded Result: 0.2>

Använder decimalklass för hög precision

Dedecimal>modulen gerDecimal>klass, vilket möjliggör aritmetik med högre precision. Ställa in precisionen medgetcontext().prec>kan hjälpa till att hantera precision för specifika beräkningar

Python3




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}'>)>

java char till int
>

>

Produktion:

High Precision Result: 0.2>

Använda bråk för exakta representationer

Defractions>modulen gör det möjligt att arbeta med exakta bråkrepresentationer, vilket undviker flyttalsfel.

Python3




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

>

>

Produktion:

Exact Fractional Result: 1/5>

Hantera mellanresultat med decimaler

AnvändDecimal>klass för mellanliggande beräkningar för att minimera kumulativa fel innan du konverterar tillbaka till 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}'>)>

>

>

Produktion:

Intermediate Result: 0.2 Final Result: 0.2>

Slutsats

Ändå tänker du varför python löser inte det här problemet , det har faktiskt ingenting med python att göra. Det händer för att det är sättet som den underliggande c-plattformen hanterar flyttalstal och i slutändan med felaktigheten kommer vi alltid att ha skrivit ner siffror som en sträng med fast antal siffror. Observera att detta ligger i själva naturen hos binär flyttal: det här är inte en bugg heller i Pytonorm eller C , och det är inte heller en bugg i din kod. Du kommer att se samma typ av beteenden på alla språk som stöder vår hårdvaras flyttalsaritmetik även om vissa språk kanske inte visar skillnaden som standard, eller i alla utdatalägen). Vi måste överväga detta beteende när vi bryr oss om matematiska problem med exakta behov eller använder det i villkorliga uttalanden. Kolla upp flytpunkt avsnitt i Python-dokumentationen för fler sådana beteenden.

Vanliga frågor (FAQs)

1. Vad är ett flyttalsfel i Python?

Ett flyttalsfel i Python hänvisar till avvikelser mellan förväntade och faktiska resultat när man arbetar med flyttal, som uppstår från begränsningarna för att representera reella tal i ett binärbaserat system.

2. Varför gör 1.2 - 1.0> inte jämnlikt 0.2> i Python?

Diskrepansen beror på de inneboende utmaningarna med att representera decimaltal i binärt. Avrundningsfel uppstår under den interna binära representationen, vilket leder till oväntade resultat.

3. Är flyttalsfelet ett fel i Python?

Nej, det är inte en bugg i Python. Det är ett vanligt problem inom datoranvändning relaterat till hur flyttalstal representeras internt. Python följer IEEE 754-standarden för aritmetik med flyttal.

4. Hur kan jag avrunda ett flyttalsresultat till en specifik decimal?

Du kan användaround()>funktion för att avrunda ett flyttalsresultat till en specifik decimal. Till exempel,rounded_result = round(result, 2)>.

5. Vad är decimal> modulen, och hur hjälper den att hantera flyttalsfel?

Dedecimal>modulen gerDecimal>klass för aritmetik med högre precision. Ställa in precisionen och användaDecimal>kan hjälpa till att lindra flyttalsfel.