vad är det minsta antalet större än 0? Detta är en av de enkla frågorna med komplicerade svar någonstans mellan ”det finns ingen” och ”det beror”.
om du frågar en matematiker kommer de att berätta att det inte kan finnas ett sådant nummer eftersom det skulle bryta matte. Om du har ett tal n, där n är det minsta talet efter 0, kan det inte finnas ett tal n/2, eftersom n redan är det minsta. Det betyder att uppdelningen själv bryts ner, vilket matematiker inte gillar.
om du frågar en dator får du faktiskt ett svar. I motsats till den verkliga världen har datorer inte en oändlig mängd siffror eftersom de helt enkelt inte kunde passa. Datorer lagrar nummer i minnesregister, och varje register har ett fast antal bitar. Tänk om du bara hade tre siffror. Det största antalet du kan representera skulle vara 999. Detta är vad som händer i en dator.
detta innebär att uppsättningen heltal i en dator begränsas av antalet siffror. I en dator finns det definitivt ett största antal (till exempel INT_MAX
i C). Det är numret med det maximala antalet siffror, som alla är inställda på en binär 1
. På ett 8-bitars system skulle detta nummer vara 11111111
.
vi kan komplicera saker ännu mer genom att inkludera negativa tal. Om vi har 8 bitar data kan vi använda den första biten för att representera tecknet på numret. 0
för plus och 1
för minus. Nu har vi 7 bitar för våra siffror, så det största antalet är 011111111
vilket är mindre än vårt tidigare största antal.
vi är fortfarande inte färdiga. Vi måste också representera decimaltal. Även om 0,12 är ett litet tal har det fortfarande tre siffror, precis som 123. Skillnaden är att det finns en sak vi behöver tänka på: decimalpunkten, även kallad radixpunkten. Vi måste lagra både siffrorna och radixpunktens position.
medan heltal är begränsade i hur stora de kan vara, är decimaltal begränsade i både storlek och precision. Om du har ett fast antal siffror finns det bara så många siffror du kan sätta efter decimalpunkten. Det är därför datorer behöver runda decimaltal.
hur lagrar vi dessa decimaltal då? Datorer förstår bara heltal, så vi behöver ett sätt att lagra ett decimaltal endast med heltal.
säg att vi har numret 3.14
. Låt oss börja med att skriva våra alla siffror i numret. Vi får 314
. Det är en början. Vi vet att genom att multiplicera med krafter på 10 kan vi ”flytta” decimalpunkten runt numret. 314 * 10^-1
är 31,4, medan 314 * 10^-2
är 3,14.
allt vi behöver för att representera numret 3.14 är tre heltal: 314, 10 och -2. 314 är vad som kallas en significand, och detta är alla siffror i numret skrivs ut.
10 kallas en radix eller en bas. Vi vet att genom att multiplicera med krafter på 10 kan vi flytta decimalpunkten runt siffror i bas 10. Samma fungerar för alla nummerbaser: i BAS 2 (eller binär) kan du flytta punkten genom att multiplicera med krafter på 2.
kraften vi växlar med kallas exponenten, och den berättar var decimalpunkten är.
du kan skriva varje decimaltal som de tre siffrorna med en enkel formel:
number = significand * base^exponent3.14 = 314 * 10^-2
32.8 = 328 * 10^-1
en dator lagrar ett decimaltal genom att lagra tecknet, exponenten och signifikansen i en enda sträng med 32 eller 64 bitars siffror. Vanligtvis finns det 1 bit för tecknet, 11 bitar för att lagra exponenten och 53 bitar för att lagra signifikansen och lägga till upp till 64.
med det i åtanke, låt oss komma tillbaka till vår fråga: Vad är det minsta icke-nolltalet? Om vi bara har tre siffror att spara är det minsta möjliga numret 0,01. Med fyra siffror är det 0,001. Du kommer att märka ett mönster här: signifikansen är alltid densamma, bara exponenten ändras.
vad vi behöver är en betydelse av 1
, för det är den minsta efter 0
. Vi måste sedan flytta decimalpunkten så långt vi kan till vänster. För att göra detta behöver vi den minsta (mest negativa) möjliga exponenten.
hur liten, beror på layouten av numret i minnet. Om vi har 11 bitar för exponenten kan vi bara skriva ut ett tal som är 10 bitar långt, med 1 bit reserverad för tecknet. I ett 64-bitarssystem är den minsta exponenten -308
.
i slutändan skulle det minsta möjliga antalet i ett 64-bitars system vara runt 1 * 10^-308
. Det är litet!
vi konstaterade att det finns ett minsta antal. Detta nummer berättar hur mycket vi kan lita på vår dator. Om du gör något som kräver mycket stora siffror eller mycket exakta siffror måste du ha detta nummer i åtanke.
vad vi just beräknat är något som kallas enheten i den sista platsen, eller ulp, av 0. Bortsett från att vara en riktigt cool ord, ulp berättar vad som är det minsta avståndet mellan två siffror i en dator. Vi beräknade ulp på 0, vilket är det minsta avståndet mellan 0 och nästa nummer.
om du lägger till det beräknade värdet till 0 och försöker jämföra dem, skulle de inte vara samma nummer. Men om du lägger till ett värde som är mindre än ulp, skulle det fortfarande vara samma nummer vad gäller datorn.
print(0 == 0 + ulp(0)) // false
print(0 == 0 + ulp(0) / 2) // true
för oss är det uppenbart att lägga till ett icke-nollvärde till ett tal kommer att producera ett annat tal, men en dator måste runda någonstans, så det kan inte nödvändigtvis berätta om två siffror är desamma.
för att jämföra datorsystem lättare använder vi ulp på 1 och kallar det maskinen epsilon. När du väl känner till maskinen epsilon kan du beräkna någon annan ulp med följande formel:
ulp(x) = machine epsilon * radix^exponent(x)
värdet vi beräknade är väldigt litet, så du kommer förmodligen inte att nå den gränsen när du kodar. Men vi beräknade värdet för 0. Med fler siffror som behövs för vänster sida av decimalpunkten, desto färre har vi för höger sida. Det betyder att ju större antal, desto mindre precision har du. Med andra ord är ulp en direkt funktion av exponenten. När du flyttar decimalpunkten till höger ökar ulp och du förlorar precisionen.
jag hoppas att den här informationen hjälper dig nästa gång du får ett konstigt flytpunktsfel i din kod. Kom ihåg att datorer är ganska kraftfulla, men även en dator har sina gränser.