Python, laajalti käytetty ohjelmointikieli, on erinomainen numeerisissa laskentatehtävissä, mutta se ei kuitenkaan ole immuuni liukulukuaritmetiikkaan liittyville haasteille. Pythonin liukulukuluvut ovat reaalilukujen likiarvoja, jotka johtavat pyöristysvirheet, tarkkuuden menetys ja peruutukset joka voi horjuttaa laskelmia. Me voimme huomaa nämä virheet etsimällä outoja tuloksia ja työkalujen käyttöänumpy.finfo>to monitorin tarkkuutta . Tietyllä varovaisuudella ja ovelilla temppuilla voimme pidä nämä virheet kurissa ja varmistamme, että Python-laskelmamme ovat luotettavia. Tässä artikkelissa tutkimme liukulukuvirheiden monimutkaisuutta Python .
Mitä ovat liukulukuluvut?
Liukulukuluvut ovat tehokas tapa esittää reaalilukuja tietokoneissa. Ne koostuvat kolmesta osasta:
- Merkittävä: Numeroa edustavat todelliset numerot (esim. 3,14159)
- Eksponentti: Kertoo kuinka monessa paikassa merkitsevä arvoa on siirrettävä vasemmalle tai oikealle (esim. -2 in 3,14159 x 10^-2)
- Perus: Tyypillisesti 2 tietokoneille, mikä määrittää kuinka numerot esitetään sisäisesti
Miksi liukulukuvirheitä tapahtuu?
Liukulukuvirheet syntyvät, koska tietokoneet tallentavat reaalilukuja käyttämällä äärellistä bittimäärää, mikä johtaa likiarvoihin ja mahdollisiin epätarkkuuksiin. Liukulukuluvuilla on sisäisiä rajoituksia:
- Rajallinen tarkkuus: Merkintään voidaan tallentaa vain rajoitettu määrä numeroita, mikä johtaa pyöristysvirheet kun edustaa tarkkoja desimaalilukuja.
- Tarkkuuden menetys: Toiminnot, kuten yhteen- tai vähennyslasku, voivat edelleen vähentää tarkkuutta, mikä lisää pyöristyksen vaikutuksia.
- Ali-/ylivuoto: Erittäin pienet tai suuret luvut voivat jäädä edustavan alueen ulkopuolelle, mikä johtaa alivuoto (muuttuu nollaksi) tai ylivuoto (muuttuu äärettömäksi).
Liukupistevirheiden tyypit
a) Pyöristysvirheet: Yleisin, esiintyy, kun tarkka desimaali on likimääräinen, jotta se sopisi kellukkeen rajoitettuun tarkkuuteen.
b) Tarkkuuden menetys: Myöhemmät toiminnot voivat vähitellen kerätä pyöristysvirheitä, mikä johtaa merkittäviin epätarkkuuksiin lopputulokseen.
c) Katastrofaalinen peruutus: Kun vähennetään lähes yhtä suuret luvut vastakkaisilla etumerkeillä, niiden merkitsevät numerot häviävät, jolloin tuloksena on pieni ja epätarkka.
d) Ylivuoto/alivuoto: Näitä esiintyy, kun laskelmat ylittävät kelluvien arvojen edustavan alueen, mikä johtaa epätarkkoihin tai merkityksettömiin tuloksiin.
Liukuvapistevirheiden havaitseminen
- Odottamattomien tulosten havaitseminen: Laskettujen arvojen vertaaminen odotettuihin tuloksiin tai tietojen visualisointi voi paljastaa usein virheistä johtuvia epäjohdonmukaisuuksia.
- Käyttämällä kirjastoja, kuten
numpy.finfo>: Kirjastot pitävätnumpy>tarjota työkaluja, kutenfinfo>tarkistaaksesi eri float-tietotyyppien tarkkuuden ja rajoitukset.
Python-liukulukuvirhe
Tässä keskustelemme erilaisista esimerkeistä, jotka kuvaavat Pythonin liukulukuvirheitä:
Tarkkuuden menetys desimaali-binäärimuunnoksessa
Tässä esimerkissä desimaaliluku 0,1 muunnetaan binäärilukuksi. 0,1:n äärettömästä binäärilaajennuksesta johtuen vain rajallinen määrä bittejä käytetään, mikä johtaa tarkkuuden menettämiseen.
Python 3
decimal_number>=> 0.1> binary_representation>=> format>(decimal_number,>'.30f'>)># 30 decimal places> print>(f>'Decimal: {decimal_number}
Binary: {binary_representation}'>)> |
>
>
Lähtö:
Decimal: 0.1 Binary: 0.100000000000000005551115123126>
Pyöristysvirheet
Tässä kolmen kerran 1/3:n lisäyksen tuloksen odotetaan olevan 1,0. Kuitenkin pyöristysvirheiden vuoksi 1/3:n esittämisessä summa ei välttämättä ole täsmälleen 1,0.
Python 3
result>=> 1.0> /> 3.0> sum_result>=> result>+> result>+> result> print>(f>'Expected Result: 1.0
Actual Result: {sum_result}'>)> |
>
>
Lähtö:
Expected Result: 1.0 Actual Result: 1.0>
Iteratiivisten laskelmien kumulatiiviset virheet
Tämä esimerkki osoittaa, kuinka kumulatiivisia virheitä voi esiintyä iteratiivisissa laskelmissa. 0,1:n lisääminen kymmenen kertaa ei välttämättä anna tarkkaa tulosta 1,0 liukulukutarkkuuden rajoitusten vuoksi.
Python 3
total>=> 0.0> for> i>in> range>(>10>):> >total>+>=> 0.1> print>(f>'Expected Result: 1.0
Actual Result: {total}'>)> |
>
>
Lähtö:
Expected Result: 1.0 Actual Result: 0.9999999999999999>
Vertailuongelmat
Tässä tapauksessa summan 0,1 ja 0,2 vertailu 0,3:een ei välttämättä anna odotettua tulosta.True>tulos johtuu liukulukujen luontaisesta epätarkkuudesta.
Python 3
a>=> 0.1> +> 0.2> b>=> 0.3> print>(f>'a: {a}
b: {b}
Equal: {a == b}'>)> |
>
>
Lähtö:
a: 0.30000000000000004 b: 0.3 Equal: False>
Odottamattomia tuloksia laskelmissa
Tässä vähennys1e16>summasta(1e16 + 1)>odotetaan antavan 1, mutta liukulukuvirheiden vuoksi tulos ei välttämättä ole täsmälleen 1.
deterministiset äärelliset automaatit
Python 3
a>=> 0.1> +> 0.2> b>=> 0.3> print>(f>'a: {a}
b: {b}
Equal: {a == b}'>)> |
>
>
Lähtö:
Expected Result: 1 Actual Result: 0.0>
Liukulukutarkkuuden ymmärtäminen
Tässä ymmärrämme liukulukutarkkuuden: Pythonin 1.2 – 1.0 poikkeama
Edustuksen haasteet
java silmukat
Kuten tiedetään, 1,2 – 1,0 = 0,2. Mutta kun yrität tehdä saman Pythonissa, yllätyt tuloksista:
>>> 1.2 - 1.0>
Lähtö:
0.199999999999999996>
Tätä voidaan pitää virheenä Pythonissa, mutta se ei ole sitä. Tällä ei ole juurikaan tekemistä Pythonin kanssa ja paljon enemmän sen kanssa, miten taustalla oleva alusta käsittelee liukulukuja. Se on normaali tapaus, joka kohdataan, kun liukulukuja käsitellään järjestelmän sisällä. Se on ongelma, joka johtuu liukulukujen sisäisestä esityksestä, joka käyttää kiinteää määrää binäärilukuja edustamaan desimaalilukua. Joitakin desimaalilukuja on vaikea esittää binäärimuodossa, joten monissa tapauksissa se johtaa pieniin pyöristysvirheisiin. Tiedämme samanlaisia tapauksia desimaalimatematiikassa, monia tuloksia ei voida esittää kiinteällä määrällä desimaalilukuja, Esimerkki
10 / 3 = 3.33333333.......>
Tässä tapauksessa esimerkkinä 1,2, 0,2:n esitys binäärimuodossa on 0,00110011001100110011001100…… ja niin edelleen. Tätä ääretöntä desimaalilukua on vaikea tallentaa sisäisesti. Normaalisti kelluvan objektin arvo tallennetaan binaariseen liukulukuan kiinteällä tarkkuudella ( tyypillisesti 53 bittiä ). Edustamme siis 1.2 sisäisesti kuin,
1.0011001100110011001100110011001100110011001100110011>
Mikä on täsmälleen yhtä suuri kuin:
1.1999999999999999555910790149937383830547332763671875>
Liukulukuvirheen käsittely
Tässä keskustelemme eri esimerkistä liukulukuvirheiden käsittelemisestä Pythonissa:
Pyöristys tiettyyn desimaaliin
Pyöristämällä tuloksen tiettyyn desimaaliin (esim. 2), voit lieventää pienten liukulukuvirheiden vaikutusta.
Python 3
result>=> 1.2> -> 1.0> rounded_result>=> round>(result,>2>)> print>(f>'Original Result: {result}
Rounded Result: {rounded_result}'>)> |
>
>
Lähtö:
Original Result: 0.19999999999999996 Rounded Result: 0.2>
Desimaaliluokan käyttö korkeaan tarkkuuteen
Thedecimal>moduuli tarjoaaDecimal>luokkaa, mikä mahdollistaa suuremman tarkkuuden aritmeettisen. Tarkkuuden asettaminen painikkeellagetcontext().prec>voi auttaa hallitsemaan tiettyjen laskelmien tarkkuutta
Python 3
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}'>)> |
>
>
Lähtö:
High Precision Result: 0.2>
Murtolukujen käyttäminen tarkkoihin esityksiin
Thefractions>moduuli mahdollistaa työskentelyn tarkkojen murtolukuesitysten kanssa välttäen liukulukuvirheet.
Python 3
from> fractions>import> Fraction> result>=> Fraction(>'1.2'>)>-> Fraction(>'1.0'>)> print>(f>'Exact Fractional Result: {result}'>)> |
>
>
Lähtö:
Exact Fractional Result: 1/5>
Välitulosten käsittely desimaalilla
KäytäDecimal>luokka välilaskutoimituksia varten kumulatiivisten virheiden minimoimiseksi ennen muuntamista takaisin kelluvaksi.
Python 3
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}'>)> |
>
>
Lähtö:
Intermediate Result: 0.2 Final Result: 0.2>
Johtopäätös
Silti mietit miksi python ei ratkaise tätä ongelmaa , itse asiassa sillä ei ole mitään tekemistä pythonin kanssa. Se tapahtuu, koska se on tapa, jolla alla oleva c-alusta käsittelee liukulukuja, ja viime kädessä olemme aina kirjoittaneet numeroita muistiin kiinteiden numeroiden merkkijonona. Huomaa, että tämä on binääriliukupisteen luonteeseen liittyvää: tämäkään ei ole vika Python tai C , eikä se ole myöskään vika koodissasi. Näet samanlaisen käyttäytymisen kaikilla kielillä, jotka tukevat laitteistomme liukulukuaritmetiikkaa, vaikka kaikki kielet eivät välttämättä näytä eroa oletuksena tai kaikissa tulostustiloissa. Meidän on otettava tämä käyttäytyminen huomioon, kun välitämme matemaattisista ongelmista, jotka tarvitsevat tarkan tarkkuuden tai käytämme sitä ehdollisten lauseiden sisällä. Tarkistaa liukuluku python-dokumentaation osiosta lisää tällaisia käyttäytymistä.
Usein kysytyt kysymykset (FAQ)
1. Mikä on liukulukuvirhe Pythonissa?
Pythonin liukulukuvirhe viittaa eroihin odotettujen ja todellisten tulosten välillä, kun työskennellään liukulukujen kanssa, mikä johtuu reaalilukujen esittämisen rajoituksista binääripohjaisessa järjestelmässä.
2. Miksi tekee 1.2 - 1.0> ei tasa-arvoinen 0.2> Pythonissa?
Ero johtuu desimaalilukujen esittämiseen binäärimuodossa liittyvistä luontaisista haasteista. Pyöristysvirheitä tapahtuu sisäisen binääriesityksen aikana, mikä johtaa odottamattomiin tuloksiin.
3. Onko liukulukuvirhe Pythonin bugi?
Ei, se ei ole Pythonin vika. Se on yleinen ongelma laskennassa, joka liittyy siihen, kuinka liukulukuluvut esitetään sisäisesti. Python noudattaa IEEE 754 -standardia liukulukuaritmetiikassa.
4. Kuinka voin pyöristää liukulukutuloksen tiettyyn desimaaliin?
Voit käyttää
round()>funktio pyöristää liukulukutuloksen tiettyyn desimaaliin. Esimerkiksi,rounded_result = round(result, 2)>.
5. Mikä on decimal> moduuli, ja miten se auttaa käsittelemään liukulukuvirheitä?
The
decimal>moduuli tarjoaaDecimal>luokka tarkempaan aritmetiikkaan. Tarkkuuden asettaminen ja käyttöDecimal>voi auttaa lieventämään liukulukuvirheitä.