Programmering

Flydende aritmetik

Velkommen til en anden rate af Under kølerhjelmen. Denne kolonne har til formål at give Java-udviklere et glimt af den skjulte skønhed under deres kørende Java-programmer. Denne måneds kolonne fortsætter diskussionen, der blev påbegyndt sidste måned, af bytecode-instruktionssættet på den virtuelle Java-maskine (JVM). Denne artikel tager et kig på flydende aritmetik i JVM og dækker bytekoderne, der udfører aritmetiske operationer med flydende punkt. Efterfølgende artikler vil diskutere andre medlemmer af bytecode-familien.

De vigtigste flydende punkter

JVM's flydepunktsstøtte overholder IEEE-754 1985-flydepunktsstandarden. Denne standard definerer formatet på 32-bit og 64-bit floating-point numre og definerer operationerne på disse numre. I JVM udføres aritmetik med flydende punkt på 32-bit floats og 64-bit double. For hver bytecode, der udfører aritmetik på floats, er der en tilsvarende bytecode, der udfører den samme operation på double.

Et flydende nummer har fire dele - et tegn, en mantissa, en radix og en eksponent. Tegnet er enten 1 eller -1. Mantissaen, der altid er et positivt tal, indeholder de signifikante cifre i det flydende nummer. Eksponenten indikerer den positive eller negative effekt af radixen, som mantissen og tegnet skal ganges med. De fire komponenter kombineres som følger for at få flydende punktværdien:

tegn * mantissa * radix eksponent

Flydende numre har flere repræsentationer, fordi man altid kan multiplicere mantissaen for ethvert flydende nummer med en eller anden effekt af radixen og ændre eksponenten for at få det originale nummer. F.eks. Kan tallet -5 repræsenteres ens af en hvilken som helst af følgende former i radix 10:

Formularer på -5
SkiltMantissaRadix-eksponent
-15010 -1
-1510 0
-10.510 1
-10.0510 2

For hvert flydende nummer er der en repræsentation, der siges at være normaliseret. Et flydende nummer normaliseres, hvis dets mantissa er inden for det område, der er defineret af følgende relation:

1 / radix <= mantissa <

Et normaliseret radix 10-flydende tal har sin decimal lige til venstre for det første ikke-nul ciffer i mantissen. Den normaliserede flydepunktsrepræsentation på -5 er -1 * 0,5 * 10 1. Med andre ord har et normaliseret flydende punkts mantissa ingen cifre uden nul til venstre for decimaltegnet og et ikke-nul ciffer lige til højre for decimaltegnet. Ethvert flydende nummer, der ikke passer ind i denne kategori, siges at være denormaliseret. Bemærk, at tallet nul ikke har nogen normaliseret repræsentation, fordi det ikke har et ikke-nul ciffer, der skal placeres lige til højre for decimaltegnet. "Hvorfor blive normaliseret?" er et almindeligt udråb blandt nuller.

Flydende numre i JVM bruger en radix på to. Flydende numre i JVM har derfor følgende form:

tegn * mantissa * 2 eksponent

Mantissen af ​​et flydende tal i JVM udtrykkes som et binært tal. En normaliseret mantissa har sit binære punkt (base-to ækvivalent med et decimaltegn) lige til venstre for det mest betydningsfulde ikke-nul ciffer. Fordi det binære nummersystem kun har to cifre - nul og et - er det mest betydningsfulde tal i en normaliseret mantissa altid et.

Den mest betydningsfulde bit af en float eller dobbelt er dens signbit. Mantissen indtager de 23 mindst betydningsfulde bits i en float og de 52 mindst signifikante bits i en double. Eksponenten, 8 bits i en float og 11 bits i en double, sidder mellem tegnet og mantissaen. Formatet på en float er vist nedenfor. Tegnbiten vises som et "s", eksponentbittene vises som "e", og mantissabitene vises som "m":

Bit layout af Java float
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm

En tegnbit på nul angiver et positivt tal, og et tegnbit på et angiver et negativt tal. Mantissen fortolkes altid som et positivt base-to-tal. Det er ikke et to-komplement nummer. Hvis tegnbiten er en, er flydepunktværdien negativ, men mantissen fortolkes stadig som et positivt tal, der skal ganges med -1.

Eksponentfeltet fortolkes på en af ​​tre måder. En eksponent for alle indikerer, at flydende nummer har en af ​​de specielle værdier på plus eller minus uendelig eller "ikke et tal" (NaN). NaN er resultatet af visse operationer, såsom delingen af ​​nul med nul. En eksponent med alle nuller indikerer et denormaliseret floating-point-nummer. Enhver anden eksponent angiver et normaliseret floating-point-nummer.

Mantissaen indeholder en ekstra bit præcision ud over dem, der vises i mantissabitene. Mantissaen på en float, der kun optager 23 bits, har 24 bit præcision. Mantissaen af ​​en dobbelt, der optager 52 bit, har 53 bit præcision. Den mest betydningsfulde mantissabit er forudsigelig og er derfor ikke inkluderet, fordi eksponenten for floating-point-tal i JVM indikerer, om antallet er normaliseret eller ej. Hvis eksponenten alle er nuller, bliver det flydende punktummer denormaliseret, og den mest betydningsfulde bit af mantissen er kendt for at være et nul. Ellers normaliseres flydepunktet, og den mest betydningsfulde bit af mantissen vides at være en.

JVM kaster ingen undtagelser som følge af operationer med flydende punkt. Særlige værdier, som f.eks. Positiv og negativ uendelighed eller NaN, returneres som et resultat af mistænkelige operationer såsom deling med nul. En eksponent af alle indikerer en særlig værdi for flydende punkt. En eksponent for alle dem med en mantissa, hvis bits alle er nul, indikerer en uendelighed. Uendelighedens tegn er angivet med tegnbiten. En eksponent for alle dem med enhver anden mantissa fortolkes som "ikke et tal" (NaN). JVM producerer altid den samme mantissa for NaN, som alle er nuller bortset fra den mest betydningsfulde mantissabit, der vises i nummeret. Disse værdier vises for en float nedenfor:

Specielle flydeværdier
VærdiFlydebit (tegn eksponent mantissa)
+ Uendelighed0 11111111 00000000000000000000000
-Uendelighed1 11111111 00000000000000000000000
NaN1 11111111 10000000000000000000000

Eksponenter, der hverken er alle ens eller alle nuller, angiver styrken af ​​to, hvormed den normaliserede mantissa multipliceres. Effekten af ​​to kan bestemmes ved at fortolke eksponentbitene som et positivt tal og derefter trække en bias fra det positive tal. For en float er forspændingen 126. For en dobbelt er forspændingen 1023. For eksempel giver et eksponentfelt i en float på 00000001 en styrke på to ved at trække forspændingen (126) fra eksponentfeltet fortolket som et positivt heltal (1). Kraften i to er derfor 1 - 126, hvilket er -125. Dette er den mindste mulige effekt af to til en float. På den anden ekstreme giver et eksponentfelt på 11111110 en effekt på to af (254 - 126) eller 128. Nummeret 128 er den største effekt af to tilgængelige for en float. Flere eksempler på normaliserede flyder er vist i følgende tabel:

Normaliserede floatværdier
VærdiFlydebit (tegn eksponent mantissa)Upartisk eksponent
Største positive (endelige) flyde0 11111110 11111111111111111111111128
Største negative (endelige) flyde1 11111110 11111111111111111111111128
Mindste normaliserede flyde1 00000001 00000000000000000000000-125
Pi0 10000000 100100100001111110110112

En eksponent for alle nuller indikerer, at mantissen er denormaliseret, hvilket betyder, at den ikke-angivne ledende bit er nul i stedet for en. Kraften af ​​to i dette tilfælde er den samme som den laveste effekt af to til rådighed for en normaliseret mantissa. For float er dette -125. Dette betyder, at normaliserede mantissas ganget med to hævet til magten af ​​-125 har et eksponentfelt på 00000001, mens denormaliserede mantissas ganget med to hævet til styrken af ​​-125 har et eksponentfelt på 00000000. Tillægget for denormaliserede tal nederst slutningen af ​​rækken af ​​eksponenter understøtter gradvis understrømning. Hvis den laveste eksponent i stedet blev brugt til at repræsentere et normaliseret tal, ville der forekomme understrømning til nul for større tal. Med andre ord, hvis man efterlader den laveste eksponent for denormaliserede tal, kan mindre tal blive repræsenteret. De mindre denormaliserede tal har færre præcisionsbits end normaliserede tal, men dette er at foretrække frem for understrømning til nul, så snart eksponenten når sin minimum normaliserede værdi.

Denormaliserede flydeværdier
VærdiFlydebit (tegn eksponent mantissa)
Mindste positive (ikke-nul) float0 00000000 00000000000000000000001
Mindste negative (ikke-nul) float1 00000000 00000000000000000000001
Største denormaliserede flyde1 00000000 11111111111111111111111
Positivt nul0 00000000 00000000000000000000000
Negativt nul1 00000000 00000000000000000000000

Udsat svømmer

En Java-float afslører sin indre natur Applet'en nedenfor giver dig mulighed for at lege med floating-point-formatet. Værdien af ​​en float vises i flere formater. Radix to-videnskabelige notationsformat viser mantissa og eksponent i base ti. Inden den vises, multipliceres den aktuelle mantissa med 2 24, hvilket giver et integralt tal, og den objektive eksponent reduceres med 24. Både den integrerede mantissa og eksponent konverteres derefter let til base ti og vises.