Ohjelmointi

Liukulukuinen laskutoimitus

Tervetuloa toiseen erään Konepellin alle. Tämän sarakkeen tarkoituksena on antaa Java-kehittäjille oivallus piilotetusta kauneudesta heidän käynnissä olevien Java-ohjelmiensa alla. Tämän kuukauden sarake jatkaa viime kuussa aloitettua keskustelua Java-virtuaalikoneen (JVM) tavukoodikäskyjoukosta. Tässä artikkelissa tarkastellaan liukulukujen aritmeettisuutta JVM: ssä ja käsitellään tavukoodeja, jotka suorittavat liukulukuaritmeettisia operaatioita. Myöhemmissä artikkeleissa keskustellaan muista tavukoodiperheen jäsenistä.

Tärkeimmät kelluvat pisteet

JVM: n liukulukutuki noudattaa IEEE-754 1985 -liukulukustandardia. Tämä standardi määrittelee 32- ja 64-bittisten liukulukujen muodon ja määrittelee operaatiot näillä numeroilla. JVM: ssä liukulukulaskenta suoritetaan 32-bittisillä kelluilla ja 64-bittisillä tuplailla. Jokaiselle tavukoodille, joka suorittaa aritmeettisen uimurilla, on vastaava tavukoodi, joka suorittaa saman toiminnon kaksoiskappaleilla.

Liukuluvun numerossa on neljä osaa - merkki, mantissa, radix ja eksponentti. Merkki on joko 1 tai -1. Mantissa, aina positiivinen luku, sisältää liukuluvun merkittävät numerot. Eksponentti osoittaa radiksin positiivisen tai negatiivisen voiman, jolla mantissa ja merkki tulisi kertoa. Neljä komponenttia yhdistetään seuraavasti liukulukuarvon saamiseksi:

merkki * mantissa * radix-eksponentti

Liukulukuilla on useita esityksiä, koska aina voidaan kertoa minkä tahansa liukuluvun mantissa jokin radiksin teho ja muuttaa eksponentti alkuperäisen luvun saamiseksi. Esimerkiksi lukua -5 voidaan edustaa tasaisesti millä tahansa seuraavista radiksin 10 muodoista:

Muodot -5
MerkkiMantissaRadix-eksponentti
-15010 -1
-1510 0
-10.510 1
-10.0510 2

Jokaiselle liukuluvun numerolle on yksi esitys, jonka sanotaan olevan normalisoitu. Liukuluku normalisoidaan, jos sen mantissa on seuraavan suhteen määrittelemällä alueella:

1 / radix <= mantissa <

Normisoidun radix 10 -liukuluvun desimaalipiste on vain mantissan ensimmäisen nollasta poikkeavan numeron vasemmalla puolella. -5: n normalisoitu liukuluvun esitys on -1 * 0,5 * 10 1. Toisin sanoen normalisoidun liukuluvun mantissassa ei ole nollasta poikkeavia numeroita desimaalipisteen vasemmalla puolella ja ei-nollanumero vain desimaalipilkun oikealla puolella. Kaikkien liukulukujen, jotka eivät sovi tähän luokkaan, sanotaan olevan denormalisoitu. Huomaa, että luvulla nolla ei ole normalisoitua esitystä, koska sillä ei ole nollan ulkopuolista numeroa, jonka laittaa vain desimaalipilkun oikealle puolelle. "Miksi normalisoida?" on yleinen huutomerkki nollien joukossa.

JVM: n liukulukuluvuissa käytetään kahden radiksia. JVM: n liukulukuluvuilla on siis seuraava muoto:

merkki * mantissa * 2 eksponentti

Liukulukuluvun mantissa JVM: ssä ilmaistaan ​​binäärilukuna. Normalisoidun mantissan binääripiste (kahden peruspisteen ekvivalentti) on merkittävimmän nollan ulkopuolisen numeron vasemmalla puolella. Koska binääriluvujärjestelmässä on vain kaksi numeroa - nolla ja yksi -, normalisoidun mantissan merkittävin numero on aina yksi.

Merkittävin kelluva tai kaksinkertainen bitti on sen merkkibitti. Mantissa vie kellukan 23 vähiten merkitsevää bittiä ja kaksoisosan 52 vähiten merkitsevää bittiä. Eksponentti, 8 bittiä kellukkeessa ja 11 bittiä kaksoiskappaleessa, istuu merkin ja mantissan välissä. Uimurin muoto on esitetty alla. Merkkibitti näytetään "s": nä, eksponenttibitit näytetään "e": nä ja mantissa-bitit "m":

Java-kellukkeen bittinen asettelu
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm

Nollan merkkibitti osoittaa positiivista lukua ja yhden merkkibitti negatiivista. Mantissa tulkitaan aina positiivisena kahden perusnumerona. Se ei ole kaksikommenttinen numero. Jos merkkibitti on yksi, liukuluku on negatiivinen, mutta mantissa tulkitaan silti positiivisena lukuna, joka on kerrottava -1: llä.

Eksponenttikenttä tulkitaan yhdellä kolmesta tavasta. Kaikkien eksponentti osoittaa, että liukuluvun numerolla on yksi erikoisarvoista plus tai miinus ääretön tai "ei luku" (NaN). NaN on seurausta tietyistä toiminnoista, kuten nollan jakamisesta nollalla. Kaikkien nollien eksponentti ilmaisee denormalisoidun liukuluvun. Mikä tahansa muu eksponentti ilmoittaa normalisoidun liukuluvun.

Mantissa sisältää yhden ylimääräisen tarkkuuden pidemmälle kuin ne, jotka näkyvät mantissa-paloissa. Uimurin mantissalla, joka vie vain 23 bittiä, on 24 bitin tarkkuus. Tuplan mantissalla, joka vie 52 bittiä, on 53 bitin tarkkuus. Merkittävin mantissabitti on ennustettavissa, eikä sitä siksi sisällytetä, koska liukulukujen eksponentti JVM: ssä osoittaa, onko luku normalisoitu vai ei. Jos eksponentti on kaikki nollat, kelluva luku denormalisoidaan ja mantissan merkittävimmän bitin tiedetään olevan nolla. Muussa tapauksessa liukuluku normalisoidaan ja mantissan merkittävimmän bitin tiedetään olevan yksi.

JVM ei aiheuta poikkeuksia minkään liukulukuoperaation seurauksena. Erityisarvot, kuten positiivinen ja negatiivinen ääretön tai NaN, palautetaan epäilyttävien toimintojen, kuten nollalla jakamisen, seurauksena. Kaikkien eksponentti osoittaa erityisen liukulukuarvon. Kaikkien eksponentti, jolla on mantissa, jonka bitit ovat kaikki nollia, osoittaa ääretöntä. Äärettömyyden merkki ilmaistaan ​​merkkibitillä. Kaikkien muiden kanssa esiintyvän eksponentin tulkitaan tarkoittavan "ei lukua" (NaN). JVM tuottaa aina saman mantissan NaN: lle, joka on kaikki nollat ​​lukuun ottamatta merkittävintä mantissabittiä. Nämä arvot näytetään alla olevalle uimurille:

Erityiset kellunta-arvot
ArvoKelluvat bitit (merkki eksponentti Mantissa)
+ Ääretön0 11111111 00000000000000000000000
- Äärettömyys1 11111111 00000000000000000000000
NaN1 11111111 10000000000000000000000

Eksponentit, jotka eivät ole kaikki ykkösiä tai kaikkia nollia, osoittavat kahden voiman, jolla normalisoitu mantissa voidaan kertoa. Kahden teho voidaan määrittää tulkitsemalla eksponenttibitit positiivisena lukuna ja vähentämällä sitten esijännitys positiivisesta luvusta. Kellukkeella esijännitys on 126. Kaksinkertaisen kohdalla esijännitys on 1023. Esimerkiksi kelluvan kentän 00000001 eksponenttikenttä tuottaa kahden tehon vähentämällä ennakkoarvon (126) positiivisena kokonaislukuna tulkittavasta eksponenttikentästä. (1). Siksi kahden teho on 1 - 126, mikä on -125. Tämä on kahden pienin mahdollinen voima kellukkeelle. Toisessa ääripäässä eksponenttikenttä 11111110 tuottaa kahden (254 - 126) tai 128 tehon. Luku 128 on suurin kelluvan käytettävissä oleva teho kahdesta. Seuraavassa taulukossa on useita esimerkkejä normalisoiduista uimureista:

Normalisoidut float-arvot
ArvoKelluvat bitit (merkki eksponentti Mantissa)Puolueeton eksponentti
Suurin positiivinen (äärellinen) kelluva0 11111110 11111111111111111111111128
Suurin negatiivinen (äärellinen) kelluva1 11111110 11111111111111111111111128
Pienin normalisoitu uimuri1 00000001 00000000000000000000000-125
Pi0 10000000 100100100001111110110112

Kaikkien nollien eksponentti osoittaa, että mantissa on denormalisoitu, mikä tarkoittaa, että ilmoittamaton alkubitti on nolla yhden sijasta. Kahden teho on tässä tapauksessa sama kuin normalisoidulle mantissalle käytettävissä oleva kahden alin teho. Kellukkeelle tämä on -125. Tämä tarkoittaa, että normalisoiduilla mantissoilla kerrottuna kahdella, joka on korotettu arvoon -125, eksponenttikenttä on 00000001, kun taas denormalisoiduilla mantissoilla, jotka on kerrottu kahdella, jotka on korotettu arvoon -125, on eksponenttikenttä 00000000. Denormalisoitujen numeroiden alaraja on alareunassa. eksponenttialueen loppu tukee asteittaista alivuotoa. Jos alimman eksponentin sijasta käytettäisiin normalisoitua lukua, suurempien lukujen kohdalla tapahtuisi alivirta nollaan. Toisin sanoen pienimmän eksponentin jättäminen denormalisoiduille numeroille antaa mahdollisuuden edustaa pienempiä lukuja. Pienemmillä denormalisoiduilla numeroilla on vähemmän tarkkuusbittejä kuin normalisoiduilla numeroilla, mutta tämä on parempi kuin alivirta nollaan heti, kun eksponentti saavuttaa vähimmäis normalisoidun arvon.

Denormalisoidut float-arvot
ArvoKelluvat bitit (merkki eksponentti Mantissa)
Pienin positiivinen (ei nolla) kelluva0 00000000 00000000000000000000001
Pienin negatiivinen (ei nolla) kelluva1 00000000 00000000000000000000001
Suurin denormalisoitu uimuri1 00000000 11111111111111111111111
Positiivinen nolla0 00000000 00000000000000000000000
Negatiivinen nolla1 00000000 00000000000000000000000

Paljasta kellua

Java-uimuri paljastaa sen sisäisen luonteen. Alla olevan sovelman avulla voit leikkiä liukulukuformaatilla. Uimurin arvo näytetään useissa muodoissa. Radix kaksi tieteellistä merkintämuotoa näyttää mantissan ja eksponentin peruskymmenessä. Ennen näyttämistä todellinen mantissa kerrotaan 2 24: llä, mikä antaa kokonaisluvun, ja puolueeton eksponentti vähennetään 24. Sekä integraali mantissa että eksponentti muunnetaan sitten helposti kymmeneksi ja näytetään.