Programmering

Flytende aritmetikk

Velkommen til en annen del av Under panseret. Denne kolonnen har som mål å gi Java-utviklere et glimt av den skjulte skjønnheten under deres kjørende Java-programmer. Denne månedens kolonne fortsetter diskusjonen, startet i forrige måned, av bytecode-instruksjonssettet til Java virtual machine (JVM). Denne artikkelen tar en titt på flytende-punkt-aritmetikk i JVM, og dekker bytekodene som utfører flytende-punkt-aritmetiske operasjoner. Senere artikler vil diskutere andre medlemmer av bytecode-familien.

De viktigste flytende punktene

JVMs flytpunktsstøtte overholder IEEE-754 1985 flytpunktsstandard. Denne standarden definerer formatet på 32-biters og 64-biters flytende tall og definerer operasjonene på disse tallene. I JVM utføres flytende aritmetikk på 32-bits flyter og 64-bits dobler. For hver bytekode som utfører aritmetikk på flyter, er det en tilsvarende bytekode som utfører den samme operasjonen på dobler.

Et flytende nummer har fire deler - et tegn, en mantissa, en radiks og en eksponent. Tegnet er enten 1 eller -1. Mantissaen, alltid et positivt tall, inneholder de betydelige sifrene i flytende punktnummer. Eksponenten indikerer den positive eller negative kraften til radiksen som mantissen og tegnet skal multipliseres med. De fire komponentene kombineres som følger for å få flytpunkt-verdien:

sign * mantissa * radix eksponent

Flytpunkttall har flere representasjoner, fordi man alltid kan multiplisere mantissen til hvilket som helst flytpunktsnummer med noe kraft fra radiksen og endre eksponenten for å få det opprinnelige nummeret. For eksempel kan tallet -5 representeres likt av hvilken som helst av følgende former i radix 10:

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

For hvert flytende nummer er det en representasjon som sies å være normalisert. Et flytende nummer normaliseres hvis mantissaen er innenfor området definert av følgende forhold:

1 / radix <= mantissa <

Et normalisert radix 10-flytende nummer har desimaltegnet til venstre for det første ikke-null-tallet i mantissen. Den normaliserte flytepunktrepresentasjonen på -5 er -1 * 0,5 * 10 1. Med andre ord har et normalisert flytpunktsantall ingen sifre som ikke er null til venstre for desimaltegnet og et tall som ikke er null bare til høyre for desimaltegnet. Ethvert flytende nummer som ikke passer inn i denne kategorien sies å være denormalisert. Vær oppmerksom på at tallet null ikke har noen normalisert representasjon, fordi det ikke har noe tall som ikke er null å sette bare til høyre for desimaltegnet. "Hvorfor bli normalisert?" er et vanlig utrop blant nuller.

Flytpunkttall i JVM bruker en radiks på to. Flytende nummer i JVM har derfor følgende form:

sign * mantissa * 2 eksponent

Mantissen til et flytende tall i JVM uttrykkes som et binært tall. En normalisert mantissa har sitt binære punkt (base-to-ekvivalent med et desimaltegn) like til venstre for det viktigste tallet som ikke er null. Fordi det binære tallsystemet bare har to sifre - null og ett - er det viktigste tallet i en normalisert mantissa alltid ett.

Den viktigste biten av en flottør eller dobbel er dens tegnbit. Mantissen opptar de 23 minst betydningsfulle biter av en flottør og de 52 minst betydningsfulle biter av en dobbel. Eksponenten, 8 biter i en flottør og 11 biter i en dobbel, sitter mellom skiltet og mantissaen. Formatet på en flottør er vist nedenfor. Tegnbiten er vist som et "s", eksponentbitene er vist som "e", og mantissabitene vises som "m":

Bitoppsett av Java float
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmm

En tegnbit på null indikerer et positivt tall og en tegnbit på en indikerer et negativt tall. Mantissa tolkes alltid som et positivt base-to-tall. Det er ikke et to-komplement nummer. Hvis tegnbiten er en, er flytpunktverdien negativ, men mantissa tolkes fortsatt som et positivt tall som må multipliseres med -1.

Eksponentfeltet tolkes på en av tre måter. En eksponent av alle indikerer at det flytende punktet har en av spesialverdiene pluss eller minus uendelig, eller "ikke et tall" (NaN). NaN er resultatet av visse operasjoner, for eksempel delingen av null med null. En eksponent med alle nuller indikerer et denormalisert flytende nummer. Enhver annen eksponent indikerer et normalisert flytende nummer.

Mantissen inneholder en ekstra bit presisjon utover de som vises i mantissabitene. Mantissaen til en flottør, som bare tar 23 biter, har 24 biter presisjon. Mantissaen til en dobbel, som opptar 52 bits, har 53 bits presisjon. Den mest betydningsfulle mantissabiten er forutsigbar, og er derfor ikke inkludert, fordi eksponenten for flytende punktum i JVM indikerer om tallet er normalisert eller ikke. Hvis eksponenten alle er nuller, blir det flytende punktet denormalisert, og den viktigste biten av mantissen er kjent for å være et null. Ellers normaliseres det flytende tallet og det er kjent at den viktigste biten av mantissen er en.

JVM gir ingen unntak som et resultat av flytende punktoperasjoner. Spesielle verdier, som positiv og negativ uendelig eller NaN, returneres som et resultat av mistenkelige operasjoner som divisjon med null. En eksponent for alle indikerer en spesiell flytende verdi. En eksponent for alle med en mantissa hvis biter er null indikerer en uendelig. Uendelighetstegnet er angitt med tegnbiten. En eksponent for alle sammen med en hvilken som helst annen mantissa blir tolket til å bety "ikke et tall" (NaN). JVM produserer alltid den samme mantissen for NaN, som alle er nuller bortsett fra den mest betydningsfulle mantissabiten som vises i tallet. Disse verdiene vises for en flottør nedenfor:

Spesielle flyteverdier
VerdiFlytebiter (sign eksponent mantissa)
+ Uendelig0 11111111 00000000000000000000000
-Evighet1 11111111 00000000000000000000000
NaN1 11111111 10000000000000000000000

Eksponenter som verken er alle ens eller alle nuller indikerer kraften til to som multipliserer den normaliserte mantissen. Kraften til to kan bestemmes ved å tolke eksponentbitene som et positivt tall, og deretter trekke en skjevhet fra det positive tallet. For en flottør er forspenningen 126. For en dobbel er forspenningen 1023. For eksempel gir et eksponentfelt i en flottør på 00000001 en styrke på to ved å trekke forspenningen (126) fra eksponentfeltet tolket som et positivt heltall (1). Kraften til to er derfor 1 - 126, som er -125. Dette er den minste mulige kraften av to for en flottør. På den andre ytterpunktet gir et eksponentfelt på 11111110 en kraft på to av (254 - 126) eller 128. Tallet 128 er den største kraften av to som er tilgjengelig for en flottør. Flere eksempler på normaliserte flottører er vist i følgende tabell:

Normaliserte flyteverdier
VerdiFlytebiter (sign eksponent mantissa)Upartisk eksponent
Største positive (endelige) flottør0 11111110 11111111111111111111111128
Største negative (endelige) flottør1 11111110 11111111111111111111111128
Minste normaliserte flottør1 00000001 00000000000000000000000-125
Pi0 10000000 100100100001111110110112

En eksponent med alle nuller indikerer at mantissen er denormalisert, noe som betyr at den ikke-angitte ledende biten er null i stedet for en. Kraften til to i dette tilfellet er den samme som den laveste effekten av to som er tilgjengelig for en normalisert mantissa. For flottøren er dette -125. Dette betyr at normaliserte mantissas multiplisert med to hevet til kraften -125 har et eksponentfelt på 00000001, mens denormaliserte mantissas multiplisert med to hevet til kraften -125 har et eksponentfelt på 00000000. Tillatelsen til denormaliserte tall nederst slutten av serien av eksponenter støtter gradvis understrømning. Hvis den laveste eksponenten i stedet ble brukt til å representere et normalisert tall, ville understrøm til null forekomme for større tall. Med andre ord, å la den laveste eksponenten for denormaliserte tall tillate at mindre tall blir representert. De mindre denormaliserte tallene har færre presisjonsbiter enn normaliserte tall, men dette er å foretrekke fremfor å understrømme til null så snart eksponenten når sin minimum normaliserte verdi.

Denormaliserte flyteverdier
VerdiFlytebiter (sign eksponent mantissa)
Minste positive (ikke-null) flyt0 00000000 00000000000000000000001
Minste negative (ikke-null) flyt1 00000000 00000000000000000000001
Største denormaliserte flottør1 00000000 11111111111111111111111
Positivt null0 00000000 00000000000000000000000
Negativ null1 00000000 00000000000000000000000

Utsatt flottør

En Java-flottør avslører sin indre natur Appleten nedenfor lar deg leke med flytepunktformatet. Verdien på en flottør vises i flere formater. Radix to vitenskapelige notasjonsformat viser mantissa og eksponent i base ti. Før den vises, multipliseres den faktiske mantissen med 2 24, noe som gir et integralt tall, og den objektive eksponenten blir redusert med 24. Både integral-mantissaen og eksponenten blir så lett konvertert til base ti og vises.

$config[zx-auto] not found$config[zx-overlay] not found