Hva er det minste tallet større enn 0? Dette er et av de enkle spørsmålene med kompliserte svar et sted mellom «det er ingen» og «det avhenger».
hvis du spør en matematiker, vil de fortelle deg at det ikke kan være et slikt tall fordi det ville bryte matte. Hvis du har et tall n, hvor n er det minste tallet etter 0, kan det ikke være et tall n/2, fordi n allerede er det minste. Dette betyr at splittelsen selv bryter ned, som matematikere ikke liker.
hvis du spør en datamaskin, vil du faktisk få et svar. I motsetning til den virkelige verden har datamaskiner ikke en uendelig mengde tall fordi de ganske enkelt ikke kunne passe. Datamaskiner lagrer tall i minneregistre, og hvert register har et fast antall biter. Tenk deg om du bare hadde tre sifre. Det største tallet du kan representere ville være 999. Dette er hva som skjer i en datamaskin.
Dette betyr at settet av heltall i en datamaskin er begrenset av antall siffer. I en datamaskin er det definitivt et største tall (for eksempel INT_MAX
I C). Det er tallet med maksimalt antall sifre, som alle er satt til en binær 1
. På et 8-biters system vil dette nummeret være 11111111
.
vi kan komplisere saker enda mer ved å inkludere negative tall. Hvis vi har 8 biter av data, kan vi bruke den første biten til å representere tegn på nummeret. 0
for pluss og 1
for minus. Nå har vi 7 biter for våre sifre, så det største tallet er 011111111
som er mindre enn vårt tidligere største tall.
Vi er fortsatt ikke ferdige. Vi må også representere desimaltall. Selv om 0,12 er et lite tall, har det fortsatt tre sifre, akkurat som 123. Forskjellen er at det er en ting vi må tenke på: desimalpunktet, også kalt radixpunktet. Vi må lagre både sifrene og posisjonen til radixpunktet.
mens heltall er begrenset i hvor store de kan være, er desimaltall begrenset i både størrelse og presisjon. Hvis du har et fast antall sifre, er det bare så mange sifre du kan sette etter desimalpunktet. Dette er grunnen til at datamaskiner må runde desimaltall.
hvordan lagrer vi disse desimaltallene da? Datamaskiner forstår bare heltall, så vi trenger en måte å lagre et desimaltall bare ved hjelp av heltall.
Si at vi har nummeret 3.14
. La oss begynne med å skrive våre alle sifrene i nummeret. Vi får 314
. Det er en start. Vi vet at ved å multiplisere med krefter på 10, kan vi «flytte» desimaltegnet rundt tallet. 314 * 10^-1
er 31,4, mens 314 * 10^-2
er 3,14.
Alt vi trenger for å representere tallet 3.14 er tre heltall: 314, 10 og -2. 314 er det som kalles en betydeligog dette er alle sifrene i nummeret skrevet ut.
10 kalles en radix eller en base. Vi vet at ved å multiplisere med krefter på 10 kan vi flytte desimalpunktet rundt tall i base 10. Det samme fungerer for alle tall baser: i base 2 (eller binær) kan du skifte prikken ved å multiplisere med krefter på 2.
kraften vi skifter med kalles eksponenten, og den forteller oss hvor desimalpunktet er.
du kan skrive hvert desimaltall som de tre tallene med en enkel formel:
number = significand * base^exponent3.14 = 314 * 10^-2
32.8 = 328 * 10^-1
en datamaskin lagrer et desimaltall ved å lagre tegnet, eksponenten og significand i en enkelt streng med 32 eller 64 bit sifre. Vanligvis er det 1 bit for tegnet, 11 biter for å lagre eksponenten og 53 biter for å lagre significand, og legge opp til 64.
Med det i tankene, la oss komme tilbake til spørsmålet vårt: Hva er det minste tallet uten null? Hvis vi bare har tre sifre til overs, er det minste mulige tallet 0,01. Med fire sifre er det 0,001. Du vil merke et mønster her: significand er alltid den samme, bare eksponenten endres.
det vi trenger er en significand av 1
, fordi det er den minste etter 0
. Vi må da skifte desimaltegnet så langt vi kan til venstre. For å gjøre dette trenger vi den minste (mest negative) mulige eksponenten.
hvor liten, avhenger av oppsettet av nummeret i minnet. Hvis vi har 11 biter for eksponenten, kan vi bare skrive ut et tall som er 10 biter langt, med 1 bit reservert for tegnet. I et 64-biters system er den minste eksponenten -308
.
til slutt vil det minste mulige tallet i et 64-biters system være rundt 1 * 10^-308
. Det er lite!
vi fastslått at det er et minste tall. Dette tallet forteller oss hvor mye vi kan stole på datamaskinen vår. Hvis du gjør noe som krever svært store tall eller svært presise tall, må du huske dette nummeret.
det vi nettopp har beregnet er noe som kalles enheten på siste plass, eller ulp, på 0. Bortsett fra å være et veldig kult ord, forteller ulp oss hva som er minimumsavstanden mellom to tall i en datamaskin. Vi beregnet ulp på 0, som er minimumsavstanden mellom 0 og neste nummer.
hvis du legger den beregnede verdien til 0 og prøver å sammenligne dem, ville de ikke være det samme tallet. Men hvis du legger til en verdi mindre enn ulp, vil det fortsatt være det samme nummeret så langt som datamaskinen er bekymret.
print(0 == 0 + ulp(0)) // false
print(0 == 0 + ulp(0) / 2) // true
for oss er det åpenbart at å legge til en ikke-null verdi til et tall vil produsere et annet tall, men en datamaskin må runde et sted, så det kan ikke nødvendigvis fortelle om to tall er de samme.
for å sammenligne datasystemer lettere, bruker vi ulp av 1, og kaller det maskinen epsilon. Når du kjenner maskinen epsilon, kan du beregne andre ulp med følgende formel:
ulp(x) = machine epsilon * radix^exponent(x)
verdien vi beregnet er svært liten, så du sannsynligvis ikke vil treffe den grensen mens koding. Men vi beregnet verdien for 0. Med flere sifre som trengs for venstre side av desimalpunktet, jo færre har vi til høyre side. Dette betyr at jo større tall, jo mindre presisjon du har. Med andre ord er ulp en direkte funksjon av eksponenten. Når du skifter desimalpunktet til høyre, øker ulp, og du mister presisjonen.
jeg håper denne informasjonen vil hjelpe deg neste gang du får en merkelig flyttallsfeil i koden din. Husk at datamaskiner er ganske kraftige, men selv en datamaskin har sine grenser.