Flyttal: hur datorer lagrar reella tal i binär flytande-punktsformat

Lär dig hur datorer representerar reella tal i binärt flytande-punktsformat (IEEE‑754), och hur mantissa, exponent, precision och avrundningsfel påverkar noggrannheten.

Författare: Leandro Alegsa

Reella tal i binär form måste lagras på ett speciellt sätt i en dator. Datorer representerar tal som binära heltal (hela tal som är potenser av två), så det finns inget direkt sätt för dem att representera icke-integrala tal som decimaltal eftersom det inte finns någon radixpunkt. Ett sätt för datorer att kringgå detta problem är att representera tal i ett så kallat flytande-punktsformat, där begreppet ”flytande” hänvisar till att radixpunkten kan flyttas (skjutas) genom att talet multipliceras med en exponent (potens).

Grundläggande struktur

Ett binärt flyttal består i praktiken av tre delar:

  • Teckenbit (sign): anger om talet är positivt eller negativt.
  • Exponent: bestämmer skalningen (hur långt radixpunkten flyttas).
  • Signifikand (mantissa eller betydande): innehåller de viktiga siffrorna i talet.

För normaliserade tal i ett vanligt flytande-punktsformat ges värdet av formeln

värde = (-1)^sign · 1.fraction · 2^(exponent − bias)

där 1.fraction betyder att det finns en implicit ledande etta i normaliserad form och bias är en förskjutning (offset) som lagras för att kunna representera både positiva och negativa exponenter som osignerade heltal.

IEEE 754 och vanliga format

Den dominerande standarden för flyttal är IEEE 754. De vanligaste formaten är:

  • Single precision (32 bitar): 1 bit tecken, 8 bitar exponent, 23 bitar fraction. Bias = 127.
  • Double precision (64 bitar): 1 bit tecken, 11 bitar exponent, 52 bitar fraction. Bias = 1023.

Specialfall i IEEE 754:

  • Exponent alla nollor: representerar noll (om fraction = 0) eller subnormala (denormaliserade) tal (om fraction ≠ 0). Subnormala tal saknar den implicita ledande ettan och används för att representera mycket små tal nära noll.
  • Exponent alla ettor: representerar oändlighet (om fraction = 0) eller NaN (Not a Number) om fraction ≠ 0.

Varför vissa decimaltal inte kan representeras exakt

Binär representation kan endast exakt uttrycka rationella tal vars nämnare är en potens av två. Ett tal som 0,5 (1/2) är enkelt, men många decimaltal som 0,1 (1/10) har ingen ändlig binär representation — i binärt blir 0,1 ett periodiskt (repetitivt) binärt bråktal 0.0001100110011… och måste avrundas när det lagras i ett ändligt antal bitar. Det leder till små fel i värdet.

Numeriska egenskaper och problem

  • Rundningsfel: Eftersom endast ett ändligt antal bitar lagras måste tal ofta avrundas. IEEE 754 specificerar flera avrundningslägen (vanligast är "round to nearest, ties to even").
  • Maskinprecision (machine epsilon): det minsta relativa steget mellan tal nära 1. För double är detta ungefär 2^(-52) ≈ 2.22e-16.
  • Klyvning och avstängning: När man adderar tal med mycket olika storlek kan de små talen försvinna (de blir för små för att påverka de stora talen inom den givna precisionen).
  • Katastrofal avkylning (cancellation): Subtraktion av nästan lika stora tal kan ge stort relativt fel eftersom signifikanta siffror tas bort.
  • Ej reflexiv jämförelse: Till synes lika beräkningar kan ge olika binära resultat; därför är direkta likhetskontroller (==) ofta opålitliga för flyttal.

Exempel

Exempelvis lagrar en dator ofta 0,1 som ett tal som är mycket nära men inte exakt 0,1. När man summerar 0,1 flera gånger kan man därför få ett resultat som ser oväntat ut (t.ex. 0,30000000000000004 i stället för 0,3 i dubbel precision).

Praktiska råd för programmerare

  • Använd decimal-/BigDecimal-typer eller liknande när exakt decimalrepresentation krävs (t.ex. för pengar).
  • Jämför flyttal med en tolerans (epsilon) i stället för med == när du vill avgöra om två värden är "lika".
  • Vid summering av många tal med varierande storlek kan algoritmer som Kahan summation reducera ackumulerade rundningsfel.
  • Vid behov av hög precision använd multiprecisionbibliotek (t.ex. MPFR, GMP, språkens inbyggda stora tal-klasser).
  • Var medveten om specialvärden (NaN, +Inf, −Inf) och hur de beter sig i jämförelser och beräkningar.

Sammanfattning

Binär flytande-punktslagring är en kompromiss mellan räckvidd och precision. Den gör det möjligt att representera mycket stora och mycket små tal i en begränsad mängd bitar, men innebär också rundningsfel, specialfall och numeriska fallgropar. För kritiska tillämpningar gäller det att känna till formaten (t.ex. IEEE 754), förstå dess begränsningar och använda lämpliga tekniker och datatyper beroende på problemet.

Översikt

Inom matematik och vetenskap förenklas ofta mycket stora och mycket små tal och multipliceras med en tiopotens för att göra dem lättare att förstå. Det kan till exempel vara mycket lättare att läsa 1,2 biljoner som {\displaystyle 1.2\times 10^{12}} än 1 200 000 000 000 000. Detta kan också användas med negativa tiopotenser för att skapa små tal, vilket innebär att du kan representera 0,000001 som {\displaystyle 1\times 10^{-6}}. Detta förfarande kallas vetenskaplig notation.

Eftersom datorer är begränsade till heltal och binära tal innebär det att de inte enkelt kan representera bråkdecimaltal. För att representera bråksiffror använder datorer tre uppsättningar binära tal för att skapa en vetenskaplig notation. De är: den signerade biten, som bestämmer om talet är positivt (0) eller negativt (1), signifikanten, som är en heltalsversion (hel) av talet, och exponenten, som är den potens du multiplicerar basen med.

Betydelse och

Signifikanten hittas genom att ta ditt tal och flytta radixpunkten tills det inte finns någon bråkdel, vilket gör det till ett heltal. I decimaltal är detta att göra 1,45 till 145 genom att flytta punkten två steg åt höger, och i binärtal skulle detta vara att göra 1101,0111 (13,4375) till 1101 0111 (215) genom att flytta punkten fyra steg åt höger; i båda fallen är dessa tal inte relaterade till varandra utöver att använda samma siffror i en liknande ordning.

På samma sätt som vetenskaplig notation gör signifikanten så grundläggande som möjligt, är syftet med flyttal att göra den till ett heltal så att den kan representeras i bytes och användas i beräkningar.

Exponent

Exponenten är det antal siffror som radixpunkten har flyttats förbi: om den flyttas till vänster är exponenten negativ, men om den flyttas till höger är den positiv. Som ovan krävs det att du multiplicerar med 100 för att göra 1,45 till 145, så exponenten är 2 eftersom {\displaystyle 100=10^{2}}. På samma sätt krävs det för att göra 1101.0111 (13.4375) till 1101 0111 (215) att du flyttar radixpunkten fyra kolumner till höger, så exponenten är 4. Detta kan verifieras i decimalform som {\displaystyle 215\div 13.4375=16(2^{4})} .

Eftersom processen är omvänd i de flesta fall av vetenskaplig notation, eftersom det handlar om att göra en fraktion till ett heltal i stället för att vända ett stort heltal till ett bråk, är exponenter i allmänhet negativa för att flytta decimalplatsen till vänster; i decimal skulle detta vara att vända ditt heltal 145 tillbaka till bråktalet 1,45 genom att multiplicera det med {\displaystyle 10^{-2}}. Istället för att använda en signerad bit längst till vänster är exponenten istället förskjuten, vilket ger 32-bitars float-exponenter ett intervall på {\displaystyle 2^{-126}} till {\displaystyle 2^{127}}. Utgångsvärdet för den snedvridna exponenten kan hittas genom att lägga till 127 till den:

{\displaystyle b^{5}=132(5+127)=10000100}

{\displaystyle b^{-5}=122(-5+127)=01111010}

{\displaystyle b^{0}=127(0+127)=01111111}



 

Exempel

Decimal till Bikimal

Låt oss till exempel anta att vi vill representera decimaltalet 37,40625 till dess binära motsvarighet: en bikimal (eller binär decimal/bråk). Först måste vi ta vårt decimaltal, som är i potenser av 10, och omvandla det till binärt tal, som är i potenser av 2. Ett sätt att göra detta är att subtrahera den största möjliga potensen av två tills man når noll:

{\displaystyle 37.40625-\mathbf {32} (2^{5})=5.40625}

{\displaystyle 5.40625-\mathbf {4} (2^{2})=1.40625}

{\displaystyle 1.40625-\mathbf {1} (2^{0})=0.40625}

{\displaystyle 0.40625-\mathbf {0.25} (2^{-2})=0.15625}

{\displaystyle 0.15625-\mathbf {0.125} (2^{-3})=0.03125}

{\displaystyle 0.03125-\mathbf {0.03125} (2^{-5})=0}

Med hjälp av potenser av två ovan kan vi representera vårt decimaltal {\displaystyle 37.40625} på följande sätt:

Effekt:

{\displaystyle 2^{5}}

{\displaystyle 2^{4}}

{\displaystyle 2^{3}}

{\displaystyle 2^{2}}

{\displaystyle 2^{1}}

{\displaystyle 2^{0}}

-

{\displaystyle 2^{-1}}

{\displaystyle 2^{-2}}

{\displaystyle 2^{-3}}

{\displaystyle 2^{-4}}

{\displaystyle 2^{-5}}

Värde:

1

0

0

1

0

1

-

0

1

1

0

1

Bicimal till Float

Vi har bekräftat att vårt decimaltal {\displaystyle 37.40625} representeras binärt som {\displaystyle 100101.01101} . Problemet med datorer är dock att de representerar tal som hela potenser av två med hjälp av bitar, vilket gör det komplicerat med bråktal och negativa tal. I enlighet med IEEE-754 är det vanligaste sättet att göra detta med en dator att skapa ett 32-bitars flyttal som består av tre delar: tecknet, 1 bit för att avgöra om vårt tal är positivt eller negativt, exponenten, 8 bitar för att representera exponenten och till vilken vi adderar 127 för att undvika signerade bytes, och vår signifikant, som är vårt binära tal utan tvåkommapunkt fördelat på 23 bitar. Eftersom vi måste flytta vår bicimalpunkt 5 platser för att göra {\displaystyle 100100.01101} till signifikanten {\displaystyle 10010001101} är vår exponent {\displaystyle 132(5+127)} . Genom att använda en 32-bitars float kan vi representera 37,40625 på följande sätt:

Typ:

±

Exponent

Betydelse och

Värde:

0

1

0

0

0

0

1

0

0

0

0

1

0

1

0

1

1

0

1

0

0

0

0

0

0

0

0

0

0

0

0

0

Betydelse:

+

{\displaystyle 2^{7}+2^{2}=132}

{\displaystyle 2^{20}+2^{18}+2^{16}+2^{15}+2^{13}=1,417,216}



 

Relaterade sidor

 

Frågor och svar

F: Vad är reella tal?


S: Reella tal är alla tal som kan uttryckas som decimaltal, inklusive bråk och irrationella tal.

F: Hur lagrar datorer binära tal?


S: Datorer lagrar binära tal som binära heltal, som är hela tal som är potenser av två.

F: Finns det ett direkt sätt för datorer att representera icke-integrala tal som decimaltal?


S: Nej, det finns inget direkt sätt för datorer att representera icke-integrala tal som decimaltal eftersom det inte finns någon radixpunkt.

F: Vad är syftet med representation av flyttal?


S: Med hjälp av flyttalsrepresentation kan datorer kringgå problemet med att det inte finns någon radixpunkt genom att låta radixpunkten flyttas högre eller lägre när den multipliceras med en exponent (potens).

F: Vad betyder "floating" i flytpunktsrepresentation?


S: Termen "flytande" avser hur radixpunkten kan flyttas högre eller lägre när den multipliceras med en exponent (potens).

F: Hur beräknar man en exponent (potens)?


S: En exponent (potens) beräknas genom att multiplicera ett bastal med sig självt ett visst antal gånger. Till exempel 2^3 = 8 eftersom 2 x 2 x 2 x 2 = 8.


Sök
AlegsaOnline.com - 2020 / 2025 - License CC3